简体   繁体   English

谁能解释我为什么这个特征不能正常工作?

[英]Could anyone explain me why this trait does not work properly?

I tried to write a trait to check if a class has static function, but it always gives me the false. 我试图写一个特征来检查一个类是否具有静态功能,但是它总是给我错误。 Could anyone tell me where is the problem? 谁能告诉我问题出在哪里?

#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;
}

The following code works: 以下代码有效:

#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;
}

Seems like there is not big difference between these examples. 这些示例之间似乎并没有太大差异。

Could anyone make me understand where is the problem of first code? 谁能让我明白第一个代码的问题在哪里?

Note to C++17, 17.5.7.2 says, that 注意C ++ 17,17.5.7.2说,

When a template-id refers to the specialization of an alias template, it is equivalent to the associated type obtained by substitution of its template-arguments for the template-parameters in the type-id of the alias template. 当template-id指代别名模板的特殊化时,它等效于通过将其模板参数替换为别名模板的type-id中的模板参数而获得的关联类型。 [ Note: An alias template name is never deduced. [注意:不会推导别名模板名称。 — end note ] —尾注]

This is one step process and subsequent template argument substitution never applies here. 这是一个一步的过程,后续的模板参数替换在此不再适用。

Lets play with your first example: 让我们开始第一个示例:

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 {};

Now you can see, that: 现在您可以看到:

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

Interestingly your idea with void_t works because of C++17, 17.5.7.3 有趣的是与你的想法void_t发挥作用是因为C ++ 17 17.5.7.3

However, if the template-id is dependent, subsequent template argument substitution still applies to the template-id 但是,如果template-id是依赖的,则随后的模板参数替换仍然适用于template-id

I recommend to use struct-based not alias-based templates whenever possible. 我建议尽可能使用基于结构而不是基于别名的模板。 Otherwise to make it work will be as hard as to kindle its self-immolation 否则,使其工作就像点燃其自焚一样困难。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM