sky*_*ack 13 c++ gcc templates clang variadic-templates
我无法找到更好的标题,但如果你有正确的想法,可以随意修改它.事实上,无论如何,它比GCC vs clang要好.
我试图找出这段代码中的错误:
template <typename... T>
struct S;
template <typename T, typename... U>
struct S<T, U...>: S<U...> {
using S<U...>::f;
template<void(*F)(const T &)>
void f() { }
};
template<>
struct S<> {
void f();
};
template<typename... T>
struct R: S<T...> {
using S<T...>::f;
template<typename U, void(*F)(const U &)>
void g() {
this->template f<F>();
}
};
void h(const double &) { }
int main() {
R<int, double> r;
r.g<double, h>();
}
Run Code Online (Sandbox Code Playgroud)
它用GCC 4.9编译(见这里),但不能用clang 3.8.0编译(见这里).
哪个编译器是对的,为什么?
此外,我怎么能看到编译器编译的代码?
我相信clang在这里是正确的,这是一个gcc bug.首先,让我们从一个简化的例子开始:
struct U {
template<int > void foo() { }
};
struct X : U {
using U::foo;
template<void* > void foo() { }
};
int main() {
X{}.foo<1>(); // gcc ok, clang error
}
Run Code Online (Sandbox Code Playgroud)
当using声明将基类的声明带入派生类时,派生类中的成员函数和成员函数模板会覆盖和/或隐藏具有相同名称的成员函数和成员函数模板parameter-type-list(8.3. 5),cv-qualification和基类中的ref-qualifier(如果有的话)(而不是冲突).这些隐藏或重写的声明被排除在using声明引入的声明集之外.
U::foo
并X::foo
具有相同的名称,参数类型列表(无†),cv-qualification(无)和ref限定符(无).因此,X::foo
隐藏 U::foo
而不是重载它,我们肯定传递错误的类型X::foo
.
简单地重载不同的函数指针类型(而不是将它们作为模板参数)工作正常:
template <typename T, typename... U>
struct S<T, U...> : S<U...> {
using S<U...>::f;
void f(void (*F)(const T&)) { }
};
Run Code Online (Sandbox Code Playgroud)
或者,如果您确实需要函数指针作为模板参数,仍然可以通过将它们包装在标记类型中来重载:
template <class T>
using fptr = void(*)(const T&);
template <class T, fptr<T> F>
using func_constant = std::integral_constant<fptr<T>, F>;
Run Code Online (Sandbox Code Playgroud)
并传播通过:
template <typename T, typename... U>
struct S<T, U...>: S<U...> {
using S<U...>::f;
template <fptr<T> F>
void f(func_constant<T, F> ) { }
};
Run Code Online (Sandbox Code Playgroud)
和:
template <class U, fptr<U> F>
void g() {
this->f(func_constant<U, F>{});
}
Run Code Online (Sandbox Code Playgroud)
† 参数类型列表的定义未提及模板参数.
归档时间: |
|
查看次数: |
273 次 |
最近记录: |