Deducing first template argument with other template parameters defaulted
Asked Answered
S

2

19

Gcc and clang seem to disagree on whether this code should compile or not:

#include <type_traits>

template <typename Signature, int N = 0>
struct MyDelegate { };

template <typename D>
struct signature_traits;

template <template <typename> class Delegate, typename Signature>
struct signature_traits<Delegate<Signature>>
{
    using type = Signature;
};

static_assert(std::is_same_v<
    void(int, int),
    signature_traits<MyDelegate<void(int, int)>>::type
>);

See godbolt output here and try it. I'm siding with clang here, but what does the C++ standard say about this?

A follow-up question - can this be made to work in clang?

Savell answered 25/1, 2018 at 15:54 Comment(0)
H
20

This is perfectly valid code, and gcc is right. The "feature" was introduced in C++17. It's not really a feature because it is a defect report. MyDelegate matches the partial specialization of signature_traits, and so it should be taken as gcc correctly does. Note that it works because the second template parameter is defaulted.

The reason why clang doesn't compile it is because that defect report has a defect :P. It doesn't introduce the appropriate change in partial ordering, which is not really nice and makes previousy valid code ambiguous again.

It is expected to be fixed soon, but in the meanwhile, clang decided to "hide" the feature behind a flag, -frelaxed-template-template-args.

So, just compile with that flag enabled and you should be fine.

Hypnotize answered 25/1, 2018 at 16:22 Comment(0)
I
0

The problem is that MyDelegate doesn't match template <typename> class because receive two template parameter: a type (Signature) and an int (N).

Yes: the second one has a default value. But the signature remain template <typename, int> class.

So I suppose g++ is wrong (compiling without error) and clang++ is right. Rakete1111 corrected me (thanks!): your code was wrong before C++17 but correct starting from C++17 (see his answer for the references). So (you're compiling C++17) g++ is right and clang++ is wrong.

A possible solution (waiting for a correct clang++) is define signature_traits as follows

template <template <typename, int=0> class Delegate, typename Signature>
struct signature_traits<Delegate<Signature>>
{
    using type = Signature;
};

or, better IMHO, adding the integer parameter

template <template <typename, int> class Delegate, typename Signature, int N>
struct signature_traits<Delegate<Signature, N>>
{
    using type = Signature;
};

Observe that both solutions are compatible with

static_assert(std::is_same<
    void(int, int),
    typename signature_traits<MyDelegate<void(int, int)>>::type
>::value);
Iso answered 25/1, 2018 at 16:15 Comment(5)
Actually, gcc is right. See P0522Hypnotize
@Hypnotize - you (and g++) are right; I didn't know at all of this C++17 improvement; thanks.Iso
You guys might want to use a compiler. One that has a developer team is not too finicky to obey the world-accepted standard. I am seriously mad at clang, given around 150 000 template-heavy lines I wrote last year that's compiling perfectly on every system as long as GCC is available. Do I really have to make an "explained to retards" version of my code?Breeze
@GézaTörök - Sorry but I don't understand the meaning of your comment. Do you say that I and Rakete1111 do not use a compiler? Here we have a question about an example of C++ code. C++ is a complex language, really complex. Sometimes is really difficult to understand if a piece o code is compatible or not with the language. Sometimes g++ and clang++ disagree about some corner cases (see my questions for some examples) and sometimes g++ is right, sometimes is clang++ the right one. I've tried to propose an alternative to works with both compilers. Is this wrong? This made me a bad programmer?Iso
@Iso I am sorry if you got offended by my comment, this wasn't my intention at all. I did not criticize your or anyone's programming skills or debate the complexity of C++, I didn't have any reason to do so either. I was just ranting about the non-standard-compliance of clang, which caused me like 100 hours overtime this week, in a way how GCC's vast superiority is pointed out. I apologize for the anger delivered along.Breeze

© 2022 - 2024 — McMap. All rights reserved.