谁能解释一下为什么这个特性不能正常工作?
Could anyone explain me why this trait does not work properly?
我试着写一个特征来检查 class 是否有静态函数,但它总是给我错误。谁能告诉我问题出在哪里?
#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;
}
这些例子之间似乎没有太大区别。
谁能告诉我第一个代码的问题在哪里?
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. [ Note: An alias template name is never deduced. —
end note ]
这是一步过程,后续模板参数替换从不适用于此。
让我们玩你的第一个例子:
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
的想法可行
However, if the template-id is dependent, subsequent template argument
substitution still applies to the template-id
我建议尽可能使用 struct-based 而不是 alias-based 模板。否则,让它发挥作用就像点燃它一样困难 self-immolation
我试着写一个特征来检查 class 是否有静态函数,但它总是给我错误。谁能告诉我问题出在哪里?
#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;
}
这些例子之间似乎没有太大区别。
谁能告诉我第一个代码的问题在哪里?
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. [ Note: An alias template name is never deduced. — end note ]
这是一步过程,后续模板参数替换从不适用于此。
让我们玩你的第一个例子:
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
的想法可行
However, if the template-id is dependent, subsequent template argument substitution still applies to the template-id
我建议尽可能使用 struct-based 而不是 alias-based 模板。否则,让它发挥作用就像点燃它一样困难 self-immolation