受这个答案的启发,我尝试复制并粘贴(并在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()
函数中,我使用const char*
参数调用foo
,这应该导致x
和y
为0
。但事实并非如此。在尝试编译它时,我遇到了一个奇怪的错误:
我当时就像“什么?”。我为什么要那样做...我明确使用了error: could not convert '
{0, a}
' from '<brace-enclosed initializer list>
' to 'std::tuple<int, double>
'
std::is_same
来启用return {0, a}
,只有当a
的类型被推断为double
时才会出现。所以我赶紧跑到cppreference上看if-constexpr。在页面底部,在Notes上面,我们可以看到这段代码:
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;
}
完成了!代码编译并按预期执行。那么,我的问题是 - 在这种情况下,我们是否需要在if-else
语句中的每个if
语句后面加上constexpr
?还是只有我的编译器需要?我正在使用GCC 7.3。
constexpr
是有意为之的,以显示您不必具有x
的定义,因为else块(请参见答案)会被丢弃。 - Rakete1111if
语句仍需标记为constexpr
。即使foo
是constexpr
,函数内部的所有内容也不一定都是constexpr
的(因为你仍然可以在运行时调用该函数)。 - Rakete1111else
不是一个完整的语句,它只是其中的一部分。 - T.C.