std::declval<T>(), SFINAE and deleted constructor
std::declval<T>(), SFINAE and deleted constructor
在 C++11 中使用 SFINAE 进行方法检测,我写了这个运行小示例:
#include <type_traits>
struct Foo
{
Foo();// = delete;
Foo(int);
void my_method();
};
template <typename T, typename ENABLE = void>
struct Detect_My_Method
: std::false_type
{
};
template <typename T>
struct Detect_My_Method<T, decltype(T().my_method())>
: std::true_type
{
};
int main()
{
static_assert(!Detect_My_Method<double>::value, "");
static_assert(Detect_My_Method<Foo>::value, "");
}
按预期工作。
但是,如果我删除 Foo 的空构造函数:
struct Foo
{
Foo() = delete;
Foo(int);
void my_method();
};
该示例不再有效,我收到此错误消息:
g++ -std=c++11 declVal.cpp
declVal.cpp: In function ‘int main()’:
declVal.cpp:33:3: error: static assertion failed
static_assert(Detect_My_Method<Foo>::value, "");
问题:解释以及如何解决这个问题?
删除空构造函数时,构造:
decltype(Foo().my_method());
不再有效,编译器立即投诉
error: use of deleted function ‘Foo::Foo()’
一种解决方案是使用std::decval<T>()
将任何类型 T 转换为引用类型,从而可以使用 decltype 表达式中的成员函数,无需 通过构造函数。
因此替换:
template <typename T>
struct Detect_My_Method<T, decltype(T().my_method())>
: std::true_type
{
};
由
template <typename T>
struct Detect_My_Method<T, decltype(std::declval<T>().my_method())>
: std::true_type
{
};
解决了问题。
吸取的教训:
decltype(Foo().my_method()); // invalid
decltype(std::declval<Foo>().my_method()); // fine
不等同。
此外,还有另一种定义测试的方法,它既不需要指向对象的引用或指针,也不需要函数的特定签名:
template<class T>
typename std::is_member_function_pointer<decltype(&T::my_method)>::type test_member_function_my_method(int);
template<class T>
std::false_type test_member_function_my_method(...);
template<class T>
using has_member_function_my_method = decltype(test_member_function_my_method<T>(0));
用法:
static_assert(!has_member_function_my_method<double>::value, "");
static_assert(has_member_function_my_method<Foo>::value, "");
相关文章:
- 为什么使用SFINAE而不是函数重载
- 如何使用模板函数的函数签名进行SFINAE
- 数据成员SFINAE的C++17测试:gcc vs clang
- 使用在用于SFINAE的void_t中具有参数的方法
- C++核心准则 C35 对于接口类"A base class destructor should be either public and virtual, or protected and nonv
- 为什么C++逐位AND运算符在不同大小的操作数中表现为这样
- 为什么 Clang 不允许"and"作为函数名称?
- 编译器如何在使用SFINAE的函数和标准函数之间确定两者是否可行
- 位阵列上的快速AND运算
- 是否可以在 C++03 中定义'move-and-swap idiom'等效项
- 提供与TMP和SFINAE的通用接口
- "Inverse SFINAE"避免模棱两可的过载
- BoostPython and CMake
- OpenSSL BIO and SSL_read
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- Gurobi GRBModel and GRBmodel in C++
- 如何在儿童类中使用SFINAE
- SFINAE: Understanding void_t and detect_if
- std::declval<T>(), SFINAE and deleted constructor
- Boost Fusion invoke and SFINAE