如何static_assert
在一个constexpr
函数中正确执行?例如:
constexpr int do_something(int x)
{
static_assert(x > 0, "x must be > 0");
return x + 5;
}
Run Code Online (Sandbox Code Playgroud)
这不是有效的C++ 11代码,因为constexpr函数必须只包含return语句.我不认为该标准有例外,但GCC 4.7不允许我编译这段代码.
std::initializer_list
由编译器从大括号括起的init列表构造,并且该列表的大小必须是编译时常量.
那么为什么委员会决定从模板参数中省略大小呢?这可能会阻止一些优化并使一些事情变得不可能(std::array
从a 初始化std::initializer_list
).
我正在使用std::array<size_t, N>
(N是一个固定的模板变量).
#include<array>
template<size_t N>
struct A{
size_t function(std::array<size_t, N> arr){ return arr[N-1];} // just an example
};
int main(){
A<5> a;
a.function({{1,2,3,4,5}}));
}
Run Code Online (Sandbox Code Playgroud)
它工作正常.问题是这个其他代码是默默允许的:
A.function({{1,2,3}}));
Run Code Online (Sandbox Code Playgroud)
也就是说,即使错过了元素,也会以array
某种方式初始化,即使它被很好地定义(例如,剩余元素初始化为零,我不确定)这可能是错误的来源.
有没有办法强制执行额外元素的初始化?例如,通过生成编译器错误或警告.
我想到的一个选择是使用 initializer_list
size_t function2(std::initializer_list<size_t> il){ assert(il.size() == N); ...}
Run Code Online (Sandbox Code Playgroud)
问题是,这最多会产生运行时错误并检查每次调用.我更喜欢编译器错误/警告.
我没有受到默认初始化的困扰,std::array<>{}
而是由不完整的初始化所困扰.(也许没有什么可以做的,因为这是从T[N]
静态数组的行为继承而来的.)
我试过用clang 3.5
和gcc 5
.
我试图在编译时确定a std::initializer_list
中的所有值是否唯一.我找到了一个解决方案,以确定列表的大小,但无法将其应用于内容.我已尝试使用自由函数和构造函数,但这两种方法都导致GCC 4.7.2出现以下错误.
错误:静态断言
错误的非常量条件:'begin'不是常量表达式
我意识到std::initializer_list
没有声明成员,constexpr
但我希望有一个像尺寸验证的解决方案.是否可以使用以下内容在编译时验证内容?
#include <initializer_list>
template<typename InputIterator>
constexpr bool Validate(InputIterator begin, InputIterator end)
{
static_assert(*begin == *end, "begin and end are the same");
// The actual implemetnation is a single line recursive check.
return true;
}
template<typename InputType>
constexpr bool Validate(const std::initializer_list<InputType>& input)
{
// "-1" removed to simplify and eliminate potential cause of error
return Validate(input.begin(), input.end() /* - 1 */);
}
int main()
{
Validate({1, 2, 1});
}
Run Code Online (Sandbox Code Playgroud) 在这个例子中,是否可以允许推导 的模板参数类型tuple
?
#include<tuple>
#include<string>
template<class T1, class T2>
void fun(std::tuple<T1, T2> t, std::string other){}
int main(){
fun(std::tuple<double, int>(2.,3), std::string("other")); // ok
fun(std::make_tuple(2.,3), std::string("other")); // ok, but trying to avoid `make_tuple`
fun({2.,3},std::string("other")); // desired syntax but
// giving compilation error: candidate template ignored: couldn't infer template argument 'T1' void fun(std::tuple<T1, T2> t)
}
Run Code Online (Sandbox Code Playgroud)
我添加了第二个参数,other
以避免涉及函数级别的可变参数的解决方案fun
。另外,我试图避免使用make_tuple
,至少在用户代码中(即在main()
)。事实上,它不需要是tuple
所涉及的类型,只要允许“所需的语法”,并且可以在稍后阶段以某种方式推断出其元素类型。
(另外,虽然相似,但这无关,initializer_list
因为它在大括号中具有不同的元素根本不起作用)
它至少在clang 3.2
和时失败gcc 4.7.2
。它是否有希望与当前或不久的将来的标准兼容?(例如未来(?)initializer_tuple
。)
(这对于通过聚合子元素来增加函数调用的表现力非常有用,但这可以争论)
注意:对于示例代码,似乎std::forward_as_tuple …