Reputation: 8860
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
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