【问题标题】:Return type deduction for template in-class friend functions in clangclang 中模板类内友元函数的返回类型推导
【发布时间】:2018-07-12 13:32:50
【问题描述】:

所以在前面,我想要做的并不是课堂上朋友定义的真正预期用例。但它确实可以在 g++ 下工作,而且据我所知,它应该可以根据 C++14 规范工作。

出于讨论的目的,clang 是 5.0.0,gcc 是 7.2.0,尽管我已经使用其他最新版本和 HEAD 版本进行了测试并得到了相同的结果。使用 c++14 标志编译的所有内容。

我感兴趣的案例的最小复制如下。

#include <iostream>

auto foo();

template <typename T>
class Foo
{
    friend auto foo()
    {
        return (T)3.14;
    }
};

template <typename T>
void bar(T){}

int main()
{
    bar(Foo<float>{});
    std::cout << foo() << std::endl;
    return 0;
}

Gcc 行为:编译并运行。输出:3.14

Clang 行为:拒绝编译。错误:“foo”的类型冲突

这本身似乎是完全错误的,但是由于当我删除 Foo 的模板化时 auto 不会给 clang 带来任何问题,所以我决定尝试给 foo 函数一个虚拟模板。

#include <iostream>

template <typename X = int>
auto foo();

template <typename T>
class Foo
{
    template <typename X>
    friend auto foo()
    {
        return (T)3.14;
    }
};

template <typename T>
void bar(T){}

int main()
{
    bar(Foo<float>{});
    std::cout << foo() << std::endl;
    return 0;
}

Gcc 行为:编译并运行。输出:3.14

Clang 行为:编译并运行。输出:3

是的,当使用 clang 编译时,foo 的类型推导完全取决于声明中的默认模板参数,尽管没有出现在定义中的任何地方。 o_O

最后,我决定尝试通过引入 using 指令来修复这种特殊行为。

#include <iostream>

template <typename X = int>
auto foo();

template <typename T>
class Foo
{
    using Type = T;
    template <typename X>
    friend auto foo()
    {
        return (Type)3.14;
    }
};

template <typename T>
void bar(T){}

int main()
{
    bar(Foo<float>{});
    std::cout << foo() << std::endl;
    return 0;
}

Gcc 行为:编译并运行。输出:3.14

Clang 行为:编译器崩溃。我尝试过的每个版本。

崩溃是一个明显的错误,但我对前两个示例更感兴趣。这也是clang中的错误吗?或者是否有一些微妙的原因可以解释为什么这应该是未定义的行为,而我只是对 gcc 感到幸运?更重要的是,谁能想到一种适用于 gcc 和 clang 的解决方法?我正在尝试做的事情是检测 Foo 实例化的类型,前提是它是唯一的,在编译时从 Foo 外部。

【问题讨论】:

    标签: templates g++ c++14 friend clang++


    【解决方案1】:

    虽然我仍然不完全确定 Clang 为何会这样,但我找到了一种可以在 Clang 和 GCC 上编译的解决方法。后者会引发警告,但它可以被抑制,或者可以使用 ifdefs 引入轻微的定义变化,以使代码在两者上都能干净地编译。

    #include <iostream>
    
    template <typename T = void>
    class A
    {
    public:
        friend auto foo(A<T>);
    };
    
    template <typename T>
    class Foo
    {
        friend auto foo(A<void>)
        {
            return (T)3.14;
        }
    };
    
    template <typename T>
    void bar(T){}
    
    int main()
    {
        bar(Foo<float>{});
        std::cout << foo(A{}) << std::endl;
        return 0;
    }
    

    这允许基于 Foo 实例化的模板参数推断 foo() 的返回类型,即使它们发生在不同的代码块中,这正是我所寻找的。​​p>

    【讨论】:

      猜你喜欢
      • 2015-03-12
      • 2013-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多