受this answer的启发,我试图复制并粘贴(并在main()
中添加测试)此代码:
template<typename T>
std::tuple<int, double> foo(T a) {
if constexpr (std::is_same_v<int, T>)
return {a, 0.0};
else if (std::is_same_v<double, T>)
return {0, a};
else
return {0, 0.0};
}
int main()
{
auto [x, y] = foo("");
std::cout << x << " " << y;
}
这非常简单-如果将T
推导为int
,我们想返回一个元组[a, 0.0]
。如果将T
推导为double
,我们想返回一个元组[0, a]
。否则,我们要返回[0, 0.0]
。
如您所见,在main()
函数中,我用foo
参数调用const char*
,应该产生x
并y
为0
。情况并非如此。
在尝试对其进行编译时,遇到一个奇怪的错误:
错误:无法将“
{0, a}
”从“<brace-enclosed initializer list>
”转换为“std::tuple<int, double>
”
我就像什么?。我到底为什么要...我专门使用std::is_same
来启用return {0, a}
仅,当将a
的类型推导为double
时
所以我很快在if-constexpr上运行到cppreference。在页面底部的注释上方,我们可以看到以下代码片段:
extern int x; // no definition of x required
int f() {
if constexpr (true)
return 0;
else if (x)
return x;
else
return -x;
}
我自以为是。我真的看不出原始代码有什么问题。他们使用相同的语法和语义... 。
但是我很好奇。我很好奇(也许当时)有些奇怪的东西可能解决了这个问题,所以我将原始代码更改为:
template<typename T>
std::tuple<int, double> foo(T a) {
if constexpr (std::is_same_v<int, T>)
return {a, 0.0};
else if constexpr (std::is_same_v<double, T>) // notice the additional constexpr here
return {0, a};
else
return {0, 0.0};
}
int main()
{
auto [x, y] = foo("");
std::cout << x << " " << y;
}
瞧瞧!该代码按预期方式编译和执行。因此,我的问题是-在这种情况下,我们需要在constexpr
语句中的每个if
语句之后放置if-else
吗?还是仅仅是我的编译器?我正在使用GCC 7.3。
答案 0 :(得分:43)
在这种情况下,是否需要将constexpr放在if-else块中的每个if语句之后?
是的。 else-if块 1 是一个谎言:),仅当blocks 1 和else块 1 时才存在。这是编译器如何看待您的代码:
if constexpr (std::is_same_v<int, T>)
return {a, 0.0};
else // {
if (std::is_same_v<double, T>)
return {0, a};
else
return {0, 0.0};
// }
else if (/*...*/)
只是每个人都使用的格式约定。这样,您可以清楚地看到需要第二个constexpr
。
1 :“阻止”不是正确的术语。 if是一个语句(带有可选的else部分)。阻止为{ /*...*/ }
。