问题是什么:
我正在尝试实现一个具有两种专业化的类,一种用于整数类型,一种用于所有其他类型。我想到的第一个版本:
#include <type_traits>
template<typename T, typename std::enable_if_t<std::is_integral<T>::value, bool> = true>
class Test
{
};
template<typename T, typename std::enable_if_t<!std::is_integral<T>::value, bool> = true>
class Test
{
};
Run Code Online (Sandbox Code Playgroud)
但是当我尝试编译上面的代码时,GCC 失败并出现以下错误:
<source>:2:84: error: template parameter 'typename std::enable_if<std::is_integral<_Tp>::value, bool>::type <anonymous>'
template<typename T, typename std::enable_if_t<std::is_integral<T>::value, bool> = true>
^~~~
<source>:6:85: note: redeclared here as 'typename std::enable_if<(! std::is_integral<_Tp>::value), bool>::type <anonymous>'
template<typename T, typename std::enable_if_t<!std::is_integral<T>::value, bool> = true>
^~~~
Run Code Online (Sandbox Code Playgroud)
但是,对函数使用类似的技术进行编译不会出现问题:
#include <type_traits>
template<typename T, typename std::enable_if_t<std::is_integral<T>::value, bool> = true>
void test()
{
}
template<typename T, typename std::enable_if_t<!std::is_integral<T>::value, bool> = true>
void test()
{
}
Run Code Online (Sandbox Code Playgroud)
我想要实现的目标:
我尝试过的:
使用部分特化解决了问题 2:
#include <type_traits>
template<typename T, bool = std::is_integral<T>::value>
class Test;
template<typename T>
class Test<T, true>
{
};
template<typename T>
class Test<T, false>
{
};
Run Code Online (Sandbox Code Playgroud)
但这种方法很糟糕,因为它允许使用Test<float, true>
,如果我理解正确(如果我错了,请纠正我),那么将使用整数类型的专门化,这不是我想要的。
总结:
我将以问题的形式重复我的目标:
std::enable_if
不能保证在类的模板参数列表中使用,因为该标准仅具有用于函数的 SFINAE,而不具有用于类型的 SFINAE。对于类型,它可能可用,但只能作为非标准编译器扩展。
C++20 在标准中添加了概念,这也适用于模板类上的模板参数。
template<class T>
concept NotIntegral = !std::integral<T>;
template<class T>
class Test;
template<std::integral T>
class Test<T>
{
public:
void operator()() const
{
std::cout << "integral\n";
}
};
template<NotIntegral T>
class Test<T>
{
public:
void operator()() const
{
std::cout << "not integral\n";
}
};
int main()
{
std::cout << "float: ";
(Test<float>{})();
std::cout << "int: ";
(Test<int>{})();
}
Run Code Online (Sandbox Code Playgroud)
对于以前版本的 C++,您可以将 a 添加static_assert
到类主体中,这不会阻止用户为第二个模板参数指定无效值,但至少编译代码会产生您选择的编译器错误:
template<typename T>
class Test<T, true>
{
static_assert(std::is_integral_v<T>,
"The second template parameter must contain true if and only if the first template parameter is an integral type");
};
Run Code Online (Sandbox Code Playgroud)
您可以引入一个用于创建对象的函数,而不是允许用户创建具有无效模板参数的对象:
template<typename T, bool = std::is_integral<T>::value>
class Test;
template<class T>
Test<T, std::is_integral<T>::value> MakeTest()
{
return {};
}
template<typename T>
class Test<T, true>
{
friend Test<T, std::is_integral<T>::value> MakeTest<T>();
Test() = default;
public:
void operator()() const
{
std::cout << "integral\n";
}
};
template<typename T>
class Test<T, false>
{
friend Test<T, std::is_integral<T>::value> MakeTest<T>();
Test() = default;
public:
void operator()() const
{
std::cout << "not integral\n";
}
};
int main()
{
std::cout << "float: ";
MakeTest<float>()();
std::cout << "int: ";
MakeTest<int>()();
// Test<int, false> test; // would yield a compiler error because of the inaccessible default constructor
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
134 次 |
最近记录: |