简体   繁体   English

为什么我不能在模板化的类中内联定义非模板化的朋友?

[英]Why can't I inline-define a non-templated friend within a templated class?

MCVE's speak louder than words: MCVE的言辞胜于雄辩:

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

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

with GCC 6 and --std=c++14 , this gives me: 使用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

Now, I'm not sure what the standard says; 现在,我不确定标准是什么意思; but I know that the compiler knows that the friend is not templated on B , nor does its definition use B . 但我知道编译器知道朋友没有模仿B ,它的定义也不使用B So why can't it apply the "oh, all inline copies of the same definition of a function are the same" rule? 那么为什么它不能应用“哦,函数的相同定义的所有内联副本是相同的”规则?

Now, I'm not sure what the standard says; 现在,我不确定标准是什么意思;

This case has in fact been clarified with an example in the upcoming C++17 事实上,这个案例已经在即将到来的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. [temp.inst] / 2类模板特化的隐式实例化... [snip] ...用于根据3.2 [basic.def.odr]和9.2确定成员的实例化重新声明是否有效[class.mem],与模板中的定义对应的声明被视为定义。 [ 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 ] - 结束例子]

Admittedly as you point out, the example of the standard does produce a different definition for each instantiation, but that is not necessary for the example to be ill-formed according to that rule. 不可否认,正如您所指出的那样,标准的示例确实为每个实例化生成了不同的定义,但是根据该规则,该示例不是必需的。

So why can't it apply the "oh, all inline copies of the same definition of a function are the same" rule? 那么为什么它不能应用“哦,函数的相同定义的所有内联副本是相同的”规则?

This question seems to apply to the a much simpler situation as well: 这个问题似乎也适用于一个更简单的情况:

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

Surely a compiler can see that the definitions are identical, just as much as a compiler can see that the definition of your ::bar depends not on the template argument of Foo . 当然,编译器可以看到定义是相同的,就像编译器可以看到::bar的定义不依赖于Foo的模板参数一样多。

Yet, odr says that the re-definition is ill-formed. 然而,odr说重新定义是不正确的。 This is true for definitions outside a class template, as well as definitions that are caused by instantiation of a class template. 这适用于类模板之外的定义,以及由类模板实例化引起的定义。


Perhaps odr could be relaxed for the case that you demonstrate, but that would require complicating the standard with a special case rule, and complicate the compilers that then would have to analyse whether template arguments are used within the definition, so such relaxation certainly isn't without compromise. 也许odr 可以放宽你所展示的情况,但这需要使标准与特殊情况规则复杂化,并使编译器复杂化,然后必须分析模板参数是否在定义中使用,所以这样的放松当然不是'没有妥协。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM