Freddie Chopin
Freddie Chopin

Reputation: 8860

Template argument deduction/substitution failed in a simple inheritance case

This is my minimal example:

#include <type_traits>

class Base
{
public:

    template<typename T>
    using Storage = typename std::aligned_storage<sizeof(T), alignof(T)>::type; 

    template<typename T>
    Base(Storage<T>*)
    {}
};

template<typename T>
class Derived : public Base
{
public:

    using Storage = Storage<T>;

    Derived(Storage* storage) :
            Base{storage}
    {}
};

int main()
{
    Derived<int>::Storage storage;  
    Derived<int> derived {&storage};
}

When compiling that with g++ -std=c++11 test.cpp I get this error:

test.cpp: In instantiation of ‘Derived<T>::Derived(Derived<T>::Storage*) [with T = int; Derived<T>::Storage = std::aligned_storage<4ul, 4ul>::type]’:
test.cpp:30:32:   required from here
test.cpp:23:16: error: no matching function for call to ‘Base::Base(<brace-enclosed initializer list>)’
    Base{storage}
                ^
test.cpp:23:16: note: candidates are:
test.cpp:11:2: note: template<class T> Base::Base(Base::Storage<T>*)
  Base(Storage<T>*)
  ^
test.cpp:11:2: note:   template argument deduction/substitution failed:
test.cpp:23:16: note:   couldn't deduce template parameter ‘T’
    Base{storage}
                ^

Any idea how to solve that? It seems pretty simple, yet the compiler cannot deal with it... I tried some weird casting in the construction of object, or modifications to the definition of Derived's constructor, but the errors suggested that I was going in the wrong direction...

Upvotes: 0

Views: 925

Answers (1)

David G
David G

Reputation: 96790

Your using alias introduces a non-deduced context into the Base class constructor. This causes a substitution failure because T cannot be deduced. A solution would be to deduce T through another parameter by tag-dispatching:

template<typename T>
struct no_decay { };

class Base
{
    // ...
public:
    template<typename T>
    Base(Storage<T>*, no_decay<T>);
};

// ...

Derived(Storage* storage)
    : Base(storage, no_decay<T>{})
{ }

Now T will be deduced by the second argument, not the first.

Upvotes: 2

Related Questions