我找不到更好的标题,但是如果您有正确的想法,请随时进行修改。实际上,它比GCC和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>();
}
它可以使用GCC 4.9编译(请参阅此处),但不能使用clang 3.8.0进行编译(请参阅此处)。
哪个编译器正确,为什么?
而且,我该怎么做才能看到两个编译器都在编译代码?
我相信clang在这里是正确的,这是一个gcc错误。首先,让我们从一个简化的示例开始:
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
}
当using-declaration将基类中的声明带到派生类中时,派生类中的成员函数和成员函数模板将覆盖和/或隐藏具有相同名称,parameter-type-list的成员函数和成员函数模板(8.3。 5),cv限定符和ref限定符(如果有)在基类中(而不是冲突)。此类隐藏或覆盖的声明从using-declaration引入的声明集中排除。
U::foo
并X::foo
具有相同的名称,parameter-type-list(无†),cv限定(无)和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&)) { }
};
或者,如果您确实需要将函数指针作为模板参数,则仍可以通过将其包装为标记类型来重载:
template <class T>
using fptr = void(*)(const T&);
template <class T, fptr<T> F>
using func_constant = std::integral_constant<fptr<T>, F>;
并通过以下方式传播:
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> ) { }
};
和:
template <class U, fptr<U> F>
void g() {
this->f(func_constant<U, F>{});
}
† parameter-type-list的定义未提及模板参数。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句