如果我们有一个接受3个bool类型参数的构造函数:
struct BoolOnly {
BoolOnly (bool b1, bool b2, bool b3)
{}
};
编译器验证我们实际上是用布尔参数调用它:
BoolOnly b1 {0,1,1}; //ok
BoolOnly b2 {0,1,4}; //error: narrowing conversion of ‘4’ from ‘int’ to ‘bool’
如果一个值超出了布尔值的范围,它会给出一个编译器错误,这是完全可以接受的。
现在的问题是:我想有一个可变参数模板构造函数,我想只接受bool类型的参数,换句话说,我想能够传递一个只包含0或1的初始化器,如果我传递其他参数,就会得到编译器错误
struct BoolOnlyExactVariadic {
template<typename... Args>
BoolOnlyExactVariadic (Args... args)
{}
};
这里我们不能指定任何类型的参数。这个构造函数接受任何类型的参数的任意计数。在C++中仍然不支持同质可变模板参数。
我们拥有的最先进的东西是概念--它们似乎是为设置可变参数模板参数的限制而设计的。
template<typename T>
concept BooleanExact = std::same_as<T, bool>;
struct BoolOnlyExact {
template<typename... Args>
BoolOnlyExact (BooleanExact auto... b)
{}
};
但问题是这个模板甚至不接受布尔范围内的值:
BoolOnlyExact t2 {0,0,0}; //note: the expression ‘(... && BooleanExact<auto:12>) [with auto:12 = {int, int, int}]’ evaluated to ‘false’
参数被转换成int,这不是到bool的精确转换,让我们试试std::convertible_to:
template<typename T>
concept BooleanConv = std::convertible_to<T, bool>;
struct BoolOnlyConv {
template<typename... Args>
BoolOnlyConv (BooleanConv auto... b)
{}
};
现在编译成功了,但是没有对参数值进行验证:
BoolOnlyConv t1 {4,4,5}; //ok, but we want to validate them
即使值在布尔范围之外。(不知道为什么编译器认为“5”可以转换为布尔)。
有没有C20/C23的方法可以在编译时验证一个可变初始化布尔值列表,就像第一个例子一样?除了手工写一个有15个参数的函数?这里的问题是可能有更多参数的情况(例如,9或25),对于这些情况需要单独的函数?
2条答案
按热度按时间ewm0tg9j1#
我会忘记将
0
、1
作为布尔值传递的想法,使用true
、false
,并使用std::same_as<bool>
检查类型。我看到的其他选项只有:
consteval
,并在编译时检查整数,以确保它们在范围内。template <bool...> struct BoolList {};
并将其传递给构造函数,但这会改变调用语法。rekjcdws2#
这不是一个很好的解决方案...但是如果布尔值的数量有上限(在下面的示例中为99),则可以递归地添加所需的唯一布尔构造函数
我们可以从一个简单的结构体开始,它接收一个数字作为模板参数,忽略它并将
using
类型设置为bool
然后,您可以创建一个模板递归类
AddC
(用于“add constructor”)来添加仅布尔构造函数现在
BoolOnlyExactVariadic
就变成了下面是一个完整的编译示例(
t3
变量除外,它给出了一个收缩编译错误)。