为什么我不能在模板 class 中内联定义非模板好友?
Why can't I inline-define a non-templated friend within a templated class?
MCVE 胜于雄辩:
// 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
。那么为什么它不能应用 "oh, all inline copies of the same definition of a function are the same" 规则呢?
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 ]
无可否认,正如您所指出的,标准的示例确实为每个实例化产生了一个 不同的 定义,但是根据那条规则。
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
.[=17 的模板参数一样=]
然而,odr 说重新定义的格式不正确。对于 class 模板之外的定义以及由 class 模板实例化引起的定义都是如此。
也许 odr 可以 对于您演示的情况放宽,但这需要使用特殊情况规则使标准复杂化,并使编译器复杂化,然后必须分析定义中是否使用了模板参数,所以这样的放宽当然不是没有妥协。
MCVE 胜于雄辩:
// 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
。那么为什么它不能应用 "oh, all inline copies of the same definition of a function are the same" 规则呢?
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 ]
无可否认,正如您所指出的,标准的示例确实为每个实例化产生了一个 不同的 定义,但是根据那条规则。
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
.[=17 的模板参数一样=]
然而,odr 说重新定义的格式不正确。对于 class 模板之外的定义以及由 class 模板实例化引起的定义都是如此。
也许 odr 可以 对于您演示的情况放宽,但这需要使用特殊情况规则使标准复杂化,并使编译器复杂化,然后必须分析定义中是否使用了模板参数,所以这样的放宽当然不是没有妥协。