简体   繁体   中英

Why does the variadic template argument deduction fail for this function pointer?

In the following minimal example, S::foo works, but S::bar fails.

The only difference is the order of the parameter packs Ts and Us .

struct FPtr and S::lol are the best workaround I've found, but it's rather uncomfortable to use in practice.

Why does the argument deduction for bar fail (especially since I've explicitly specified the types, so no deduction should happen at all)? Is this a compiler bug (occurs with clang++ 3.5 and g++ 4.9 ), or is this in the standard, for some reason?

template<typename ... Ts>
struct FPtr {
    FPtr(void (*val)(Ts ...)) : val{val} {}

    void (*val)(Ts ...);
};


template<typename ... Ts>
struct S {
    template<typename ... Us>
    void lol(FPtr<Us ..., Ts ...>) {}

    template<typename ... Us>
    void foo(void (*)(Ts ..., Us ...)) {}

    template<typename ... Us>
    void bar(void (*)(Us ..., Ts ...)) {}
};


void f(int, float) {}
void g(float, int) {}


int main() {
    S<int> s;

    s.lol<float>(FPtr<float, int>(g));
    s.foo<float>(f);
    s.bar<float>(g);
}

The error message is:

$ clang++ -std=c++14 t27.cpp -Wall -Wextra -pedantic
t27.cpp:31:4: error: no matching member function for call to 'bar'
        s.bar<float>(g);
        ~~^~~~~~~~~~
t27.cpp:18:7: note: candidate template ignored: failed template argument deduction
        void bar(void (*)(Us ..., Ts ...)) {}
             ^

Note: I have reported this bug on the GCC and LLVM bug trackers.

I've tested this code with both Clang and GCC and they both fail to compile the program. I'd say this is a bug in both compilers. A function parameter pack which occurs before the end of the parameter-list is a non-deduced context. After substituting the explicitly specified template argument(s) it should build the function

template<>
S<int>::bar(void (*)(float, int));

which should match the call. Clang and GCC have had problems in areas like this before and their diagnostics are known to have been less than helpful. Surprisingly however VC++ compiles the code.

Consider the following which works under both compilers.

template<class... Ts>
struct S {
    template<class... Us>
    void bar(Us..., Ts...);
};

int main() {
    S<int>().bar<int>(1, 2);
}

Your program has the same semantics and should be treated equally.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM