template template 和 CRTP: compiler bugs, GCC 和 clang 不同意
Template template and CRTP: compiler bugs, and GCC and clang do not agree
考虑以下代码,在 C++11 中,使用 g++-6
、g++-7
、clang++-3.8
和 clang++-4.0
进行测试
// Preamble
#include <iostream>
// Base 0
template <class T, template <class, T...> class Derived>
struct base0 {
void operator=(int) {std::cout << "base0::operator=\n";}
};
// Base 1
template <class T, int N, template <class, T...> class Derived>
struct base1 {
void operator=(int) {std::cout << "base1::operator=\n";}
};
// Derived 0
template <class T, int N>
struct derived0: base0<int, derived0> {
using base0::operator=; // g++6/7 = SUCCESS, clang++-3.8/4.0 = SUCCESS
using base0<int, derived0>::operator=; // g++6/7 = SUCCESS, clang++-3.8/4.0 = ERROR
};
// Derived 1
template <class T, int N>
struct derived1: base1<int, N, derived1> {
using base1::operator=; // g++6/7 = ERROR, clang++-3.8/4.0 = ERROR
using base1<int, N, derived1>::operator=; // g++6/7 = SUCCESS, clang++-3.8/4.0 = ERROR
};
// Main
int main()
{
derived0<int, 3> object0;
derived1<int, 3> object1;
object0 = 42;
object1 = 42;
return 0;
}
g++ 和 clang++ 使用相同版本的 using base::operator=
不会产生错误。哪一个是正确的,C++ 标准是怎么说的?
这是 Clang 未实现 DR1004,因此不允许 derived0/1
的 injected-class-name 用作 template-name.
GCC 对您的代码的处理似乎在所有情况下都是正确的。 0 和 1 之间的差异是由于基数在 0 中不依赖但在 1 中依赖。在前一种情况下,base0
的名称查找找到它的 injected-class-name,它可以有效地用作类型名称。在后一种情况下,名称查找会跳过相关基础并找到 ::base1
模板。
考虑以下代码,在 C++11 中,使用 g++-6
、g++-7
、clang++-3.8
和 clang++-4.0
// Preamble
#include <iostream>
// Base 0
template <class T, template <class, T...> class Derived>
struct base0 {
void operator=(int) {std::cout << "base0::operator=\n";}
};
// Base 1
template <class T, int N, template <class, T...> class Derived>
struct base1 {
void operator=(int) {std::cout << "base1::operator=\n";}
};
// Derived 0
template <class T, int N>
struct derived0: base0<int, derived0> {
using base0::operator=; // g++6/7 = SUCCESS, clang++-3.8/4.0 = SUCCESS
using base0<int, derived0>::operator=; // g++6/7 = SUCCESS, clang++-3.8/4.0 = ERROR
};
// Derived 1
template <class T, int N>
struct derived1: base1<int, N, derived1> {
using base1::operator=; // g++6/7 = ERROR, clang++-3.8/4.0 = ERROR
using base1<int, N, derived1>::operator=; // g++6/7 = SUCCESS, clang++-3.8/4.0 = ERROR
};
// Main
int main()
{
derived0<int, 3> object0;
derived1<int, 3> object1;
object0 = 42;
object1 = 42;
return 0;
}
g++ 和 clang++ 使用相同版本的 using base::operator=
不会产生错误。哪一个是正确的,C++ 标准是怎么说的?
这是 Clang 未实现 DR1004,因此不允许 derived0/1
的 injected-class-name 用作 template-name.
GCC 对您的代码的处理似乎在所有情况下都是正确的。 0 和 1 之间的差异是由于基数在 0 中不依赖但在 1 中依赖。在前一种情况下,base0
的名称查找找到它的 injected-class-name,它可以有效地用作类型名称。在后一种情况下,名称查找会跳过相关基础并找到 ::base1
模板。