考虑一个最小的例子
#include <iostream>
template<typename T>
struct foo
{
// won't compile. how to change?
static constexpr char sep[3] = std::is_integral<T>::value ? ". " : ", ";
// many other things ...
};
int main()
{
std::cout << foo<int>::sep << std::endl; // prints .
std::cout << foo<double>::sep << std::endl; // prints ,
}
我想要实现的是:
T
具有整数类型,则sep
初始化为.
sep
被初始化为,
但是,编译器不允许这样做
error: array must be initialized with a brace-enclosed initializer
似乎必须在编译时完成一些工作。但是我不确定该怎么做。
我的问题是:我能做些什么来实现这一目标吗?
注意:最小的更改是最受欢迎的。 foo
中应该还有许多其他内容。另一个考虑因素是,我想将有关foo
的所有内容保留在标头中,并尽可能在源文件中保留任何内容。
非常感谢您。
答案 0 :(得分:2)
C数组不可复制,因此您必须解决该问题
检查每个字符:
constexpr char sep[3] = { std::is_integral<T>::value ? '.' : ',', ' ', '\0' };
不要使用数组,而是使用指针(这样可以减小大小):
constexpr const char* sep = std::is_integral<T>::value ? ". " : ", ";
使用std::array
:
constexpr std::array<char, 3> sep = std::is_integral<T>::value
? std::array<char, 3>{{'.', ' ', 0}}
: std::array<char, 3>{{',', ' ', 0}};
使用对数组的引用:
constexpr char dot_sep[3] = std::is_integral<T>::value ? ". " : ", ";
constexpr char comma_sep[3] = std::is_integral<T>::value ? ". " : ", ";
constexpr const char (&sep)[3] = std::is_integral<T>::value ? dot_sep : comma_sep;
并提供ODR使用的dot_sep
/ comma_sep
的定义。
答案 1 :(得分:2)
最好的方法是使用具有特殊化功能的基类,并将sep
放在基类中:
template <bool IsIntegral>
struct foo_base;
template<>
struct foo_base<true>
{
static constexpr char sep[3] = ". ";
};
template<>
struct foo_base<false>
{
static constexpr char sep[4] = ", ";
};
template<typename T>
struct foo : foo_base<std::is_integral_v<T>>
{
// many other things ...
};
但是,如果您不希望其他人访问该库,则可以使用私有继承:
template<typename T>
struct foo : private foo_base<std::is_integral_v<T>>
{
using foo_base<std::is_integral_v<T>>::sep;
// many other things ...
};
与使用std::array<char, 3>
相比,此解决方案的优势在于,该解决方案可与接受对char的C数组的引用的函数很好地配合使用。存储const char*
和std::array<char, 3>
都没有此功能。
例如,如果您具有以下功能:
template <std::size_t I>
constexpr int count_nuls(const char (&x)[I])
{
// Can't use std::count, since it is not constexpr
unsigned count = 0;
for (auto ch: x)
if (ch == '\0')
++count;
return count;
}
此功能不能与std::array
或const char *
一起使用。如果有很多类似的功能,则可能不希望将所有功能都升级到std::array
。例如,此功能可在以下环境中完美运行:
static constexpr unsigned nuls = count_nuls(foo<double>::sep);
但是std::array<char, 3>
无法使用(未经进一步修改)。