我打算有一个只专门处理布尔或字符类型的类,而不使用boost。我的代码如下,我正在使用VS2017社区:
#include <type_traits>
template<typename T,
typename std::enable_if_t<
std::is_same<T, bool>::value || std::is_same<T, char>::value >::type >
class BoolAndCharData
{
public:
BoolAndCharData(const T& _data) {...}
void DoSomething() {...}
}; // end of class BoolAndCharData
int main()
{
char c;
BoolAndCharData<char> data(c); // error C2976: too few template parameter
....
} // end of main()
我尝试了另一种方式,因为有人在这个网站上介绍,编译器说它无法识别模板:
template<typename T>
class BoolAndCharData<T,
typename std::enable_if_t< std::is_same<T, bool>::value ||
std::is_same<T, char>::value >::type >
{
public:
BoolAndCharData(const T& _data) {...}
void DoSomething() {...}
}; // end of class BoolAndCharData
我已经浏览了这个网站和其他网站几个小时,发现虽然有很多关于限制模板类型的讨论,但大多数要么使用boots,要么特定于某个功能。我仍然不清楚如何使用选定的数据类型编写模板类。有人可以指出方法将我从盲目尝试中解救出来吗?
使用 std::enable_if_t
来做到这一点。在这种情况下,static_assert
就足够了。
举一个最小的工作示例:
#include <type_traits>
template<typename T>
class BoolAndCharData {
static_assert(std::is_same<T, bool>::value or std::is_same<T, char>::value, "!");
public:
BoolAndCharData(const T& _data) {}
void DoSomething() {}
};
int main() {
char c;
BoolAndCharData<char> d1(c);
// the following line won't compile
// BoolAndCharData<int> d2(0);
// ...
}
在科利鲁看到它。使用static_assert
时的错误也比通常从模板中得到的错误更好。
可能的解决方案如下
template <typename, typename = void>
class BoolAndCharData;
template <typename T>
class BoolAndCharData<T, std::enable_if_t<
std::is_same<T, bool>::value || std::is_same<T, char>::value > >
{
public:
BoolAndCharData(const T& _data)
{}
void DoSomething()
{}
};
主题的一点变化是定义特定的类型特征
template <typename, typename = void>
struct boolOrChar
{ };
template <typename T>
struct boolOrChar<bool, T>
{ using type = T; };
template <typename T>
struct boolOrChar<char, T>
{ using type = T; };
所以BoolAndCharData
可以写成
template <typename, typename = void>
class BoolAndCharData;
template <typename T>
class BoolAndCharData<T, typename boolOrChar<T>::type>
{
public:
BoolAndCharData(const T& _data)
{}
void DoSomething()
{}
};
您可以使用模板专用化以及通用代码的继承:
// Declares the generic case
template<typename T>
struct BoolAndCharData;
// Common base-class for the common code
template<typename T>
struct BoolAndCharDataCommon
{
explicit BoolAndCharDataCommon(T) {}
void DoSomething() {}
};
// Specialization for the char data-type
template<>
struct BoolAndCharData<char> : public BoolAndCharDataCommon<char>
{
// To use the constructor(s) from the base class
using BoolAndCharDataCommon::BoolAndCharDataCommon;
};
// Specialization for the bool data-type
template<>
struct BoolAndCharData<bool> : public BoolAndCharDataCommon<bool>
{
// To use the constructor(s) from the base class
using BoolAndCharDataCommon::BoolAndCharDataCommon;
};
int main()
{
BoolAndCharData<char> a('a');
BoolAndCharData<bool> b(false);
a.DoSomething();
b.DoSomething();
// This will lead to a compiler error
BoolAndCharData<int> c;
}
这种方式可以轻松收集所有通用代码,但如果需要,也很容易添加特定于特定类型的代码。