2

This code is accepted by GCC (several versions) and refused by clang (also several versions):

struct ACS{};

template<typename Dep>
struct AD{};

template<typename Der, typename Dep>
struct PA{
    explicit PA(ACS&) {}
};

template<typename AT, typename ADep>
struct AA : public PA< AA<AT, ADep>, AD<ADep> >
{
    using base = PA< AA<AT, ADep>, AD<ADep> >;
    using base::PA;
    // accepted by both: using base::base;
};

int main()
{
    ACS acs;
    AA<int, double> aa{acs};
}

To me, this looks like the same situation as clang doesn't see base class constructors pulled in via typedef. However, instead of a "no matching constructor" error message, clang issues this error message:

<source>:15:17: error: dependent using declaration resolved to type without 'typename'
using base::PA;
            ^

Apparently, clang expects the typename keyword. The hint suggests adding it before PA, but this:

using base:: typename PA;

is silly, and is rejected by both compilers. However, the more sensible alternative:

using typename base::PA;

is accepted without a syntax error, but now clang complains:

<source>:22:21: error: no matching constructor for initialization of 'AA<int, double>'
AA<int, double> aa{acs};
                ^ ~~~~~

In contrast, using base::base is accepted by both compilers, even without a typename. In fact, using typename base::base is accepted only by GCC; clang complains:

<source>:18:27: error: typename is allowed for identifiers only
using typename base::base;
      ~~~~~~~~~       ^

What's going on? Why is using base::PA different from using base::base? Isn't base an alias of PA?

4
  • 2
    what about using PA<AA<AT, ADep>, AD<ADep>>::PA;? Commented Feb 10 at 20:49
  • That is accepted by both (unless I also put a typename in front of the type; then clang complains). Commented Feb 10 at 21:01
  • A shorter way to define base is using base = AA::PA;. You can also write using AA::PA::PA; - both are accepted by clang. Commented Feb 11 at 0:57
  • using base = AA::PA may be shorter, but it's ill-formed: invalid use of incomplete type 'struct AA<AT, ADep>' godbolt.org/z/r5q68MTjq Commented Feb 11 at 8:02

1 Answer 1

3

Because dependent names (like PA) aren’t resolved until instantiation, using base::PA is presumed not to name a constructor; this decision must be made early because it affects parsing of the rest of the derived class template. Repeating the same name is a special case to allow inheriting dependent constructors at all; it’s very special in that base is of course not looked up in base where it wouldn’t find anything.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.