变量模板和函数指针:编译器是什么?

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编译(见这里).

哪个编译器是对的,为什么?
此外,我怎么能看到编译器编译的代码?

Bar*_*rry 9

我相信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)

来自[namespace.udecl]:

using声明将基类的声明带入派生类时,派生类中的成员函数和成员函数模板会覆盖和/或隐藏具有相同名称的成员函数和成员函数模板parameter-type-list(8.3. 5),cv-qualification和基类中的ref-qualifier(如果有的话)(而不是冲突).这些隐藏或重写的声明被排除在using声明引入的声明集之外.

U::fooX::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)

参数类型列表的定义未提及模板参数.