检查模板函数是否存在
Check the existence of a template function
如何检查模板函数是否存在:检查 reader
结构是否具有 read
算术值
struct reader {
template<typename T>
std::enable_if_t<std::is_arithmetic<T>::value, T> read() {
return {};
}
};
我使用这样的检查器:
template <typename T>
struct test_read {
static constexpr auto value = std::is_convertible<decltype(std::declval<T>().read<int>()),int>::value;
};
但是编译器抱怨:
error: wrong number of template arguments (1, should be 2)
static constexpr auto value = std::is_convertible<decltype(std::declval<T>().read<int>()),int>::value;
请给我你的建议。
谢谢。
更新:这是我讨论后得到的最终版本,希望对大家的代码有所帮助
struct not_reader {
};
struct reader {
template<typename T>
std::enable_if_t<std::is_arithmetic<T>::value, T> read() {
return {};
}
};
template<class T, class Elem>
struct has_read {
private:
template<class C, typename=void>
struct test_read : std::false_type {
};
template<class C>
struct test_read<C, typename std::enable_if<std::is_convertible<decltype(std::declval<C>().template read<Elem>()), Elem>::value>::type>
: std::true_type {
};
public:
using type = typename test_read<T>::type;
static constexpr bool value = test_read<T>::value;
};
static_assert(has_read<reader, int>::value, "reader should have int read()");
static_assert(!has_read<not_reader, int>::value, "not_reader should not have int read()");
您在 read()
之前忘记了 template
static constexpr auto value
= std::is_convertible<
decltype(std::declval<T>().template read<int>()),int>::value;
// .................................#########
但我认为您的代码无法检查“如果 reader
结构具有 read
算术值”:尝试使用 int
类型调用 test_read
并且您应该会出现编译错误。
以下是替代解决方案的示例
#include <type_traits>
struct reader
{
template<typename T>
std::enable_if_t<std::is_arithmetic<T>::value, T> read()
{ return {}; }
};
template <typename, typename = void>
struct readTypeRet
{ using type = void; };
template <typename T>
struct readTypeRet<T, decltype(std::declval<T>().template read<int>(), void())>
{ using type = decltype(std::declval<T>().template read<int>()); };
template <typename T>
struct test_read
: public std::is_convertible<typename readTypeRet<T>::type, int>
{ };
int main ()
{
static_assert(test_read<reader>::value == true, "!");
static_assert(test_read<int>::value == false, "!");
}
用更清楚的术语简要重述您的问题:
- 如果
T
满足 is_arithmetic
,你有一些函数将 return T
,否则 returns void
- 您想断言使用
int
调用此函数将 return 类型转换为 int
我认为修复代码的最短路径是利用 std::result_of
(C++11/14,在 C++17 中使用 std::invoke_result_t
):
template<class T>
struct test_read {
static constexpr auto value = std::is_convertible<
typename std::result_of<decltype(&T::template read<int>)(T)>::type, int
>::value;
};
关于此解决方案的一些说明:
- 在指定
T
(reader
)的read
成员函数时,我们需要使用template
关键字来告知编译器名字reader
是一个模板。
- 使用
result_of
需要F(Args)
的类函数语法,所以这里我们获取reader::read
的类型作为F
部分,然后传递reader
作为 Args
部分
- 我们必须传递一个
T
的实例(reader)
到read
因为它是一个成员函数(而不是static
或free),成员函数隐式引用他们被调用的 class 的实例。
如何检查模板函数是否存在:检查 reader
结构是否具有 read
算术值
struct reader {
template<typename T>
std::enable_if_t<std::is_arithmetic<T>::value, T> read() {
return {};
}
};
我使用这样的检查器:
template <typename T>
struct test_read {
static constexpr auto value = std::is_convertible<decltype(std::declval<T>().read<int>()),int>::value;
};
但是编译器抱怨:
error: wrong number of template arguments (1, should be 2)
static constexpr auto value = std::is_convertible<decltype(std::declval<T>().read<int>()),int>::value;
请给我你的建议。
谢谢。
更新:这是我讨论后得到的最终版本,希望对大家的代码有所帮助
struct not_reader {
};
struct reader {
template<typename T>
std::enable_if_t<std::is_arithmetic<T>::value, T> read() {
return {};
}
};
template<class T, class Elem>
struct has_read {
private:
template<class C, typename=void>
struct test_read : std::false_type {
};
template<class C>
struct test_read<C, typename std::enable_if<std::is_convertible<decltype(std::declval<C>().template read<Elem>()), Elem>::value>::type>
: std::true_type {
};
public:
using type = typename test_read<T>::type;
static constexpr bool value = test_read<T>::value;
};
static_assert(has_read<reader, int>::value, "reader should have int read()");
static_assert(!has_read<not_reader, int>::value, "not_reader should not have int read()");
您在 read()
template
static constexpr auto value
= std::is_convertible<
decltype(std::declval<T>().template read<int>()),int>::value;
// .................................#########
但我认为您的代码无法检查“如果 reader
结构具有 read
算术值”:尝试使用 int
类型调用 test_read
并且您应该会出现编译错误。
以下是替代解决方案的示例
#include <type_traits>
struct reader
{
template<typename T>
std::enable_if_t<std::is_arithmetic<T>::value, T> read()
{ return {}; }
};
template <typename, typename = void>
struct readTypeRet
{ using type = void; };
template <typename T>
struct readTypeRet<T, decltype(std::declval<T>().template read<int>(), void())>
{ using type = decltype(std::declval<T>().template read<int>()); };
template <typename T>
struct test_read
: public std::is_convertible<typename readTypeRet<T>::type, int>
{ };
int main ()
{
static_assert(test_read<reader>::value == true, "!");
static_assert(test_read<int>::value == false, "!");
}
用更清楚的术语简要重述您的问题:
- 如果
T
满足is_arithmetic
,你有一些函数将 returnT
,否则 returnsvoid
- 您想断言使用
int
调用此函数将 return 类型转换为int
我认为修复代码的最短路径是利用 std::result_of
(C++11/14,在 C++17 中使用 std::invoke_result_t
):
template<class T>
struct test_read {
static constexpr auto value = std::is_convertible<
typename std::result_of<decltype(&T::template read<int>)(T)>::type, int
>::value;
};
关于此解决方案的一些说明:
- 在指定
T
(reader
)的read
成员函数时,我们需要使用template
关键字来告知编译器名字reader
是一个模板。 - 使用
result_of
需要F(Args)
的类函数语法,所以这里我们获取reader::read
的类型作为F
部分,然后传递reader
作为Args
部分- 我们必须传递一个
T
的实例(reader)
到read
因为它是一个成员函数(而不是static
或free),成员函数隐式引用他们被调用的 class 的实例。
- 我们必须传递一个