2

为什么下面的代码可以用 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

我该如何解决这个问题?

4

2 回答 2

1

这是一个已修复的 gcc错误;叮当是正确的。在友元声明中指定默认参数时,

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

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

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

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

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

于 2020-08-07T07:25:26.860 回答
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>);
    // ...
}
于 2020-08-07T07:33:02.650 回答