Может ли кто-нибудь объяснить мне, почему эта черта не работает должным образом? - PullRequest
0 голосов
/ 01 июля 2019

Я пытался написать признак, чтобы проверить, имеет ли класс статическую функцию, но он всегда дает мне ложь.Может кто-нибудь сказать мне, в чем проблема?

#include <iostream>

template <template <typename...> class Trait, typename Ret, typename T>
struct is_detected : std::false_type 
{
//This helps me to check that Get_t<A> is int
static_assert(std::is_same<Trait<T>, Ret>::value, "");
};

template <template <typename...> class Trait, typename T>
struct is_detected<Trait, Trait<T>, T> : std::true_type {};

class A {
public:
  static int Get() {
    std::cout << "I'm in get\n";
    return 0;
  }
};

template <typename T>
using Get_t = decltype(T::Get());

//template <typename T>
//using supports_Get = is_detected<Get_t, int, T>;

int main() {
  std::cout << is_detected<Get_t, int, A>::value << std::endl;
  return 0;
}

Следующий код работает:

#include <iostream>
#include <type_traits>

namespace detail {
template <template <typename...> class Trait, typename V, typename T>
struct is_detected : std::false_type {};

template <template <typename...> class Trait, typename T>
struct is_detected<Trait, std::void_t<Trait<T>>, T> : std::true_type {};
}

class A {
public:
  static int Get() {
    std::cout << "I'm in get\n";
    return 0;
  }
};

template <typename T>
using Get_t = decltype(T::Get());

int main() {
  std::cout << detail::is_detected<Get_t, void, A>::value << std::endl;
  return 0;
}

Кажется, что между этими примерами нет большой разницы.

МожетКто-нибудь заставит меня понять, где проблема первого кода?

1 Ответ

0 голосов
/ 19 июля 2019

Примечание к C ++ 17, 17.5.7.2 гласит, что

Когда идентификатор шаблона относится к специализации шаблона псевдонима, он эквивалентен связанному типу, полученному путем подстановкиего аргументы шаблона для параметров шаблона в идентификаторе типа шаблона псевдонима.[Примечание: имя шаблона псевдонима никогда не выводится.- примечание конца]

Это одностадийный процесс, и последующая замена аргументов шаблона здесь не применяется.

Давайте поиграем с вашим первым примером:

template <template <typename> class Trait, typename Ret, typename T>
struct is_detected {};

struct A {
  static int Get() {
    return 0;
  }
};

template <typename T>
using Get_t = decltype(T::Get());

template <typename T>
struct Get_t2 {
  using Type = decltype(T::Get());
};

template <template <typename> class Trait, typename T>
struct is_detected<Trait, typename Trait<T>::Type, T> : std::true_type {};

template <template <typename> class Trait, typename T>
struct is_detected<Trait, Trait<T>, T> : std::true_type {};

СейчасВы можете видеть, что:

is_detected<Get_t2, int, A>::value // works, because it is normal type
is_detected<Get_t, int, A>::value // not, because it is alias

Интересно, что ваша идея с void_t работает из-за C ++ 17, 17.5.7.3

Однако, если идентификатор шаблона равензависимая, последующая замена аргумента шаблона все еще применяется к идентификатору шаблона

Я рекомендую использовать шаблоны на основе структуры, а не на основе псевдонимов, когда это возможно.Иначе заставить его работать будет так же трудно, как разжечь его самосожжение

...