基于 SFINAE 的特征实现问题与函数模板重载
SFINAE based traits implementation issue with function template overload
我正在学习 SFINAE 和特征,我知道我可以定义基于 SFINAE 的特征(在其实现中使用 SFINAE 的特征)。检测类型是否可默认构造的特征的经典实现是:
template <typename T>
struct IsDefaultConstructibleH
{
private:
template <typename U, typename = decltype(U())>
//template <typename U, const U& = U()> // WHY IS THIS ALWAYS SFINAE'd out?
static TrueType Test(void*);
template <typename>
static FalseType Test(...);
public:
using Type = decltype(Test<T>(nullptr));
};
template <typename T>
struct IsDefaultConstructible : IsDefaultConstructibleH<T>::Type
{
};
template <typename T>
constexpr bool IsDefaultConstructibleV = IsDefaultConstructible<T>::Value;
正如我在上面的代码中指出的,如果我使用注释掉的模板参数化子句(并注释掉上面的那个),如果我 运行 此代码:
#include "traits.hpp"
#include <iostream>
class Default
{
public:
Default() : mData(10) {}
private:
int mData;
};
class NoDefault
{
public:
NoDefault(int i) : mData(i) {}
private:
int mData;
};
int main(int argc, char ** argv)
{
std::cout << std::boolalpha << IsDefaultConstructible<Default>::Value << std::endl;
std::cout << std::boolalpha << IsDefaultConstructibleV<NoDefault> << std::endl;
return 0;
}
结果始终为 false false,而如果我使用另一个参数化子句(未注释掉的子句),程序会按预期给出 true、false。那么,为什么带有非类型参数的子句总是会出现 SFINAE?
作为非类型模板参数的引用类型必须是具有链接的对象的名称(通常是全局变量)。参见 https://en.cppreference.com/w/cpp/language/template_parameters#Template_non-type_arguments。它特别不能是临时的。
因此 const U& = U()
在模板中总是无效的,因为 U()
不是变量的名称(它应该看起来像 const U& = some_global_U_variable
)所以它不会被选择在 Test<T>(nullptr)
.
我正在学习 SFINAE 和特征,我知道我可以定义基于 SFINAE 的特征(在其实现中使用 SFINAE 的特征)。检测类型是否可默认构造的特征的经典实现是:
template <typename T>
struct IsDefaultConstructibleH
{
private:
template <typename U, typename = decltype(U())>
//template <typename U, const U& = U()> // WHY IS THIS ALWAYS SFINAE'd out?
static TrueType Test(void*);
template <typename>
static FalseType Test(...);
public:
using Type = decltype(Test<T>(nullptr));
};
template <typename T>
struct IsDefaultConstructible : IsDefaultConstructibleH<T>::Type
{
};
template <typename T>
constexpr bool IsDefaultConstructibleV = IsDefaultConstructible<T>::Value;
正如我在上面的代码中指出的,如果我使用注释掉的模板参数化子句(并注释掉上面的那个),如果我 运行 此代码:
#include "traits.hpp"
#include <iostream>
class Default
{
public:
Default() : mData(10) {}
private:
int mData;
};
class NoDefault
{
public:
NoDefault(int i) : mData(i) {}
private:
int mData;
};
int main(int argc, char ** argv)
{
std::cout << std::boolalpha << IsDefaultConstructible<Default>::Value << std::endl;
std::cout << std::boolalpha << IsDefaultConstructibleV<NoDefault> << std::endl;
return 0;
}
结果始终为 false false,而如果我使用另一个参数化子句(未注释掉的子句),程序会按预期给出 true、false。那么,为什么带有非类型参数的子句总是会出现 SFINAE?
作为非类型模板参数的引用类型必须是具有链接的对象的名称(通常是全局变量)。参见 https://en.cppreference.com/w/cpp/language/template_parameters#Template_non-type_arguments。它特别不能是临时的。
因此 const U& = U()
在模板中总是无效的,因为 U()
不是变量的名称(它应该看起来像 const U& = some_global_U_variable
)所以它不会被选择在 Test<T>(nullptr)
.