【问题标题】:Error for default parameter value of non-member template friend function [duplicate]非成员模板友元函数默认参数值错误[重复]
【发布时间】:2020-11-27 12:05:20
【问题描述】:

为什么下面的代码可以用 GCC 编译,但不能用 Clang?谁是对的,为什么?

class TF
{
        private:
                struct S
                {
                };

        template <typename T> friend void F(T x, S s, int v = 5);
};

template <typename T>
void F(T x, TF::S s, int v)
{
}

clang++ 出现以下错误:

    error: friend declaration specifying a default argument must be a definition
        template <typename T> friend void F(T x, S s, int v = 5);
                                          ^
    error: friend declaration specifying a default argument must be the only declaration
    void F(T x, TF::S s, int v)
         ^
    note: previous declaration is here
        template <typename T> friend void F(T x, S s, int v = 5);

GCC 版本:g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0

Clang 版本:clang 版本 6.0.0-1ubuntu2

我该如何解决这个问题?

【问题讨论】:

    标签: c++ templates default-parameters friend-function non-member-functions


    【解决方案1】:

    我该如何解决这个问题?

    正如错误消息所说,您必须定义函数模板才能具有默认参数:

        template <typename T>
        friend void F(T x, S s, int v = 5) {
            // ...
        }
    

    如果您不希望这样,您可以删除默认参数并添加充当代理的重载:

        template <typename T>
        friend void F(T x, S s, int v);
    
    // ...
    
    template <typename T>
    void F(T x, TF::S s, int v) {
        // ...
    }
    
    template <typename T>
    void F(T x, TF::S s) { F(x, s, 5); }
    

    另一种选择是对函数进行前向声明:

    template <typename T, typename S>
    void F(T x, S s, int v = 5);
    
    class TF {
    private:
        struct S {};
    
        template <typename T, typename S>
        friend void F(T x, S s, int v);
    };
    
    template <typename T, typename S>
    void F(T x, S s, int v) {
        static_assert(std::is_same_v<S, TF::S>);
        // ...
    }
    

    【讨论】:

      【解决方案2】:

      这是一个 gcc 的 bug 已修复;叮当是正确的。在朋友声明中指定default argument时,

      如果友元声明指定了默认值,则它必须是友元函数定义,并且翻译单元中不允许该函数的其他声明。

      这意味着你应该在声明它为friend的同时定义函数。

      来自标准,[dcl.fct.default]/4

      如果友元声明指定了默认参数表达式,则该声明应为定义,并且应是翻译单元中函数或函数模板的唯一声明。

      顺便说一句:Gcc 11 也不编译。

      【讨论】:

      • > “如果友元声明指定了默认参数表达式,则该声明应为定义,并且应是翻译单元中函数或函数模板的唯一声明。”...问题是为什么会有这样的规定?
      • @MeekaaSaangoo 抱歉,我也不知道,为什么委员会决定在标准中制定这样的规则。你问哪个编译器是正确的,我是根据标准回答的。您可能想问一个新的语言律师问题,即为什么存在该规则。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-29
      • 2011-05-31
      • 2014-11-08
      • 1970-01-01
      • 1970-01-01
      • 2015-07-08
      • 1970-01-01
      相关资源
      最近更新 更多