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

时间:2019-07-01 14:26:33

标签: c++ templates metaprogramming traits

我试图写一个特征来检查一个类是否具有静态功能,但是它总是给我错误。谁能告诉我问题出在哪里?

#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 :(得分:0)

注意,C ++ 17 17.5.7.2表示

  

当template-id指代别名模板的特化时,   它等效于通过替换获得的关联类型   它的type-id中的template-parameters的template-arguments   别名模板。 [注意:不会推导别名模板名称。 -   结束语]

这是一个一步的过程,后续的模板参数替换在这里不再适用。

让我们开始第一个示例:

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

有趣的是,由于C ++ 17,17.5.7.3,您对void_t的想法起作用了

  

但是,如果template-id是依赖的,则后续的模板参数   替换仍然适用于template-id

我建议尽可能使用基于结构而不是基于别名的模板。否则,使其工作就像点燃其自焚一样困难

相关问题