c++ - 为什么我不能在模板类中内联定义非模板 friend ?

标签 c++ templates language-lawyer inline friend

MCVE 胜于 Eloquent :

// int bar();
template <bool B> class Foo {
    friend int ::bar() { return 123; }
};

int main()
{
    Foo<false> f1;
    Foo<true> f2;
}

使用 GCC 6 和 --std=c++14,这给了我:

a.cpp: In instantiation of ‘class Foo<true>’:
a.cpp:9:12:   required from here
a.cpp:3:13: error: redefinition of ‘int bar()’
  friend int ::bar() { return 123; }
             ^~
a.cpp:3:13: note: ‘int bar()’ previously defined here

现在,我不确定标准是怎么说的;但我知道编译器知道 friend 没有在 B 上模板化,它的定义也没有使用 B。那么为什么它不能应用“哦,同一函数定义的所有内联拷贝都是相同的”规则呢?

最佳答案

Now, I'm not sure what the standard says;

这个案例实际上已经在即将到来的 C++17 中通过一个例子得到了澄清

[temp.inst]/2 The implicit instantiation of a class template specialization ... [snip] ... for the purpose of determining whether an instantiated redeclaration of a member is valid according to 3.2 [basic.def.odr] and 9.2 [class.mem], a declaration that corresponds to a definition in the template is considered to be a definition. [ Example:

... [snip (another example)] ...

template<typename T> struct Friendly {
  template<typename U> friend int f(U) { return sizeof(T); }
};
Friendly<char> fc;
Friendly<float> ff; // ill-formed: produces second definition of f(U)

— end example  ]

无可否认,正如您所指出的,标准的示例确实为每个实例化生成了一个不同的定义,但是根据该规则,对于格式错误的示例来说,这并不是必需的。 p>

So why can't it apply the "oh, all inline copies of the same definition of a function are the same" rule?

这个问题似乎也适用于更简单的情况:

inline void foo(){}
inline void foo(){}

当然,编译器可以看出定义是相同的,就像编译器可以看出 ::bar 的定义不依赖于 Foo.

然而,odr 说重新定义的格式不正确。对于类模板外部的定义以及由类模板实例化引起的定义都是如此。


也许 odr 可以 对于您演示的情况放宽,但这需要使用特殊情况规则使标准复杂化,并使编译器复杂化,然后编译器必须分析是否使用模板参数在定义范围内,因此这种放宽当然不是没有妥协。

关于c++ - 为什么我不能在模板类中内联定义非模板 friend ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46395724/

相关文章:

c++ - 有什么方法可以避免在 C++ 中使用非法指针吗?

C++在基类问题上返回带有模板的嵌套类

c++ - 泛化解决方案以实例化一个函数的多个模板并在运行时选择

C静态内联参数评估优化

c++ - 递归地在干草堆中查找针的索引。

C++数组意外错误

c++ - 转发声明 C 标准库实体而不是 C++ 标准库实体是否合法?

c++ - `typename` 何时可以与明确引用类型的标识符一起使用?

c++ - 不显示由 CreateFile() 函数创建的文本文件

c++ - 为什么 lambda auto& 参数选择 const 重载?