Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 846
mic_e Avatar asked May 16 '26 20:05

mic_e


1 Answers

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.

like image 160
David G Avatar answered May 18 '26 09:05

David G



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!