2

The following classes implement CRTP. I would like for class Derived to use the constructor provided by Base, so I write using. However, I get the error message, "can only inherit constructor from direct base". Equivalently for the member variable x.


template<template<typename, size_t> typename G, typename F, size_t U>
struct Base
{
    double x;
    Base(double x) : x{ x } {}
    double gimme_x()
    {
        return (*static_cast<G<F, U>*>(this)).gimme_x();
    }
};

template<typename F, size_t U>
struct Derived : Base<Derived, double, U>
{
    using Base<Derived, double, U>::Base;
    using Base<Derived, double, U>::x;

    double gimme_x()
    {
        return x + 1.8;
    }
};

This problem can be mitigated by changing the template-template implementation of Base to just use a regular template.


template<typename G, typename F, size_t U>
struct Base
{
    double x;
    Base(double x) : x{ x } {}
    double gimme_x()
    {
        return (*static_cast<G*>(this)).gimme_x();
    }
};

template<typename F, size_t U>
struct Derived : Base<Derived<F, U>, double, U>
{
    using Base<Derived<F, U>, double, U>::Base;
    using Base<Derived<F, U>, double, U>::x;

    double gimme_x()
    {
        return x + 1.8;
    }
};

While the second one looks a bit more verbose, it seems like it should be equivalent to the first one in this case. What's the difference and why does the implementation of the first one fail?

Riddick
  • 319
  • 3
  • 15

1 Answers1

1

Simpler work-around to avoid injected-class-name is to use full name ::Derived.

template<typename F, size_t U>
struct Derived : Base<Derived, double, U>
{
    using Base<::Derived, double, U>::Base;
    using Base<::Derived, double, U>::x;

    double gimme_x()
    {
        return x + 1.8;
    }
};

Demo

Code compiles correctly with both gcc/clang Demo.

It is a msvc bug, as

In the following cases, the injected-class-name is treated as a template-name of the class template itself:

  • it is followed by <
  • it is used as a template argument that corresponds to a template template parameter
  • it is the final identifier in the elaborated class specifier of a friend class template declaration.
Community
  • 1
  • 1
Jarod42
  • 203,559
  • 14
  • 181
  • 302