01函数模板中的代码,gcc13.2 及以前的编译器运行存在 bug,已在 gcc14.1 被修复
Closed this issue · 8 comments
template<typename T1,typename T2,typename RT =
decltype(true ? T1{} : T2{}) >
RT max(const T1& a, const T2& b) { // RT 是 std::string
return a > b ? a : b;
}
在gcc不能运行
https://godbolt.org/z/685Y95vKW
T1,T2不一定是可{}构造的,应用declval,且去除引用返回
需改成如下
template<typename T1,typename T2,typename RT =
std::remove_reference_t< decltype(true ?
std::declval<T1>() : std::declval<T2>())> >
RT max(const T1& a, const T2& b) { // RT 是 std::string
return a > b ? a : b;
}
T1,T2不一定是可{}构造的,应用declval,且去除引用返回
我完全清楚的知道这个问题,这是我故意为之,我并不想在此时就开始教学 std::declval,过于抽象,前期视频使用简单的 T1{}
这样的写法,带入想象 int{}
更易教学。
你可以关注到教案的后续内容,在 SFINAE 中单独拿出一节来讲这个问题:
错误的原因很简单,decltype(T{} + T{}) 这个表达式中,同时要求了 T 类型支持默认构造(虽然这不是我们的本意),然而我们的 X2 类型没有默认构造,自然而然 T{} 不是合法表达式,代换失败。其实我们之前也有类似的写法,我们在本节进行纠正,使用 std::declval
在gcc不能运行
GCC 的报错是:
error: taking address of temporary array
先留着吧,把函数调用那里换成 ::max
还实在一点,,,
我感觉这是 GCC 的 bug,至少数组和 std::string 完全可以直接({}
)构造,这里涉及到了一些其他的问题可能。
#include <iostream>
#include <type_traits>
using namespace std::string_literals;
template<typename T1, typename T2,
typename RT = decltype(true ? T1{} : T2{})>
RT max (T1 a, T2 b) {
return b < a ? a : b;
}
int main(){
auto ret = ::max("1", "2"s);
std::cout << ret << '\n';
}
gcc 可以通过编译,我只是去除了 CVR,我感觉没有道理:https://godbolt.org/z/sWWePaf99
这个 labels 怎么乱七八糟的。
是 gcc 的 bug ,已经修复了。
参考:
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102568
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94264
看起来大家都没有习惯检查 trunk 的表现……
已发布 gcc14,解决了 gcc13.2 及以前的这块 bug,再次强调一下。
https://godbolt.org/z/MWKv8roo8