Mq-b / Modern-Cpp-templates-tutorial

现代C++模板教程
https://mq-b.github.io/Modern-Cpp-templates-tutorial/
Other
662 stars 88 forks source link

01函数模板中的代码,gcc13.2 及以前的编译器运行存在 bug,已在 gcc14.1 被修复 #25

Closed Side-Cloud closed 8 months ago

Side-Cloud commented 8 months ago

https://github.com/Mq-b/Modern-Cpp-templates-tutorial/blob/main/md/%E7%AC%AC%E4%B8%80%E9%83%A8%E5%88%86-%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/01%E5%87%BD%E6%95%B0%E6%A8%A1%E6%9D%BF.md

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;
}

https://godbolt.org/z/xd14YaPx6

Mq-b commented 8 months ago

T1,T2不一定是可{}构造的,应用declval,且去除引用返回

我完全清楚的知道这个问题,这是我故意为之,我并不想在此时就开始教学 std::declval,过于抽象,前期视频使用简单的 T1{} 这样的写法,带入想象 int{} 更易教学。

你可以关注到教案的后续内容,在 SFINAE 中单独拿出一节来讲这个问题:

错误的原因很简单,decltype(T{} + T{}) 这个表达式中,同时要求了 T 类型支持默认构造(虽然这不是我们的本意),然而我们的 X2 类型没有默认构造,自然而然 T{} 不是合法表达式,代换失败。其实我们之前也有类似的写法,我们在本节进行纠正,使用 std::declval

Mq-b commented 8 months ago

在gcc不能运行

GCC 的报错是:

error: taking address of temporary array

先留着吧,把函数调用那里换成 ::max 还实在一点,,,

我感觉这是 GCC 的 bug,至少数组和 std::string 完全可以直接({})构造,这里涉及到了一些其他的问题可能。

Mq-b commented 8 months ago

@frederick-vs-ja

Mq-b commented 8 months ago
#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

rsp4jack commented 8 months ago

这个 labels 怎么乱七八糟的。

frederick-vs-ja commented 8 months ago

是 gcc 的 bug ,已经修复了。

参考:

看起来大家都没有习惯检查 trunk 的表现……

Mq-b commented 8 months ago

合理,和我猜想一样。

的确没有检查 trunk 的习惯。

https://github.com/Mq-b/Modern-Cpp-templates-tutorial/commit/ce4ce400b479970626de6e8e4fe25e28b7d95909

Mq-b commented 6 months ago

已发布 gcc14,解决了 gcc13.2 及以前的这块 bug,再次强调一下。 https://godbolt.org/z/MWKv8roo8