[英]Initialize static constexpr char array member with conditional operator in class template
Consider a minimal example 考虑一个最小的例子
#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 ,
}
What I want to achieve is: 我想要实现的是:
T
has an integral type, then sep
is initialized to .
T
具有整数类型,则sep
初始化为.
sep
is initialized to ,
sep
初始化为,
However, the compiler won't allow this, saying 但是,编译器不允许这样做,
error: array must be initialized with a brace-enclosed initializer
It looks like something must be done in compile time. 看来必须在编译时完成一些工作。 But I am not sure how to do it.
但是我不确定该怎么做。
My question is: is there anything I can do to achieve this end? 我的问题是: 我能做些什么来达到这个目的?
Note: Minimal change is most welcome. 注意:欢迎最小的更改。 There ought to be many other things in
foo
. foo
应该还有许多其他内容。 Another consideration is that I want to keep everything about foo
in header and to leave nothing in source file, if possible. 另一个考虑因素是,我想将有关
foo
所有内容保留在标头中,并在可能的情况下不保留任何源文件。
Thank you very much. 非常感谢你。
C-arrays are not copyable, so you have to work-around that C数组不可复制,因此您必须解决该问题
Do the check for each character: 对每个字符进行检查:
constexpr char sep[3] = { std::is_integral<T>::value ? '.' : ',', ' ', '\\0' };
Don't use array but pointer (so you loose size): 不要使用数组,而是使用指针(这样就可以减小大小):
constexpr const char* sep = std::is_integral<T>::value ? ". " : ", ";
Use std::array
: 使用
std::array
:
constexpr std::array<char, 3> sep = std::is_integral<T>::value ? std::array<char, 3>{{'.', ' ', 0}} : std::array<char, 3>{{',', ' ', 0}};
Use reference to array: 使用引用数组:
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;
and provide definition of dot_sep
/ comma_sep
which are ODR-used. 并提供ODR使用的
dot_sep
/ comma_sep
定义。
The best way is to use base class with specialization, and put sep
in the base class: 最好的方法是将基类与专业化一起使用,并将
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 ...
};
But if you don't want others to access the base, you can use private inheritance: 但是,如果您不希望其他人访问该库,则可以使用私有继承:
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 ...
};
The advantage of this solution over using a std::array<char, 3>
, is that this solution plays nicely with functions that accept a reference to C arrays of char. 与使用
std::array<char, 3>
相比,此解决方案的优势在于,该解决方案可以很好地与接受对char的C数组的引用的函数配合使用。 Neither storing const char*
nor std::array<char, 3>
have this capability. 存储
const char*
和std::array<char, 3>
都不具有此功能。
For example, if you have functions like: 例如,如果您具有以下功能:
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;
}
This function can't be used with std::array
, or with a const char *
. 此函数不能与
std::array
或const char *
。 If there are many functions like that, one may not want to upgrade all of them to std::array
. 如果有很多类似的功能,则可能不希望将所有功能都升级到
std::array
。 For example, this function works perfectly in: 例如,此功能在以下情况下可以完美工作:
static constexpr unsigned nuls = count_nuls(foo<double>::sep);
But won't work (without further modification) with std::array<char, 3>
. 但是不能与
std::array<char, 3>
一起使用(未经进一步修改)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.