C++: предоставление функции класса в шаблонном классе о существовании именованного члена в его шаблонном типе?

Я пытаюсь сделать следующее: шаблонный класс должен предоставлять некоторые функции, зависящие от того, содержит ли тип, с которым он был создан шаблон, переменную-член с заданным именем. В качестве примера следующий псевдокод, который должен предоставлять "printid()" только тогда, когда шаблонная структура / класс имеет член с именем "id":

#include <iostream>
#include <type_traits>

struct A { int id; };
struct B { };

template<typename T>
class foo
{
  T myvar;

public:
  #if exists T.id   (or the alternative: #if exists myvar.id)
  printid() { std::cout << "I have element id."; }
  #endif
};

int main(){
  foo<A> ok;
  ok.printid();   // should compile and execute

  foo<B> nok;
  nok.printid();  // should not compile
  return 0;
}

Копаясь в SFINAE, traits, std::enable_if и Stackru, я думаю, что это можно сделать... как угодно. Но мне почему-то не удается объединить enable_if со следующим фрагментом из вопроса " Как определить, существует ли конкретная переменная-член в классе?".:

template<typename T, typename = void>
struct has_id : std::false_type { };

template<typename T>
struct has_id<T, decltype(std::declval<T>().id, void())> : std::true_type { };

Любая помощь приветствуется.

1 ответ

Решение

Да, это возможно. Вот пример:

template<typename T>
class foo
{
  T myvar;

public:
  template <class _T = T,
            class = typename std::enable_if<
                      !std::is_function<decltype(_T::id)>::value>
                    ::type>
  void printid() { std::cout << "I have element id."; }
};

В частности, обратите внимание, как мы "принимаем" T как _T чтобы не накладывать ограничения на параметр шаблона класса (что сделало бы сам класс некомпилируемым). Вместо этого мы создаем новую независимую функцию-член шаблона, которая ничего не навязывает T сам по себе - просто "случается" использовать его в качестве аргумента по умолчанию. Это ключевая часть.

Другие вопросы по тегам