Reputation: 7775
I have an equivalent to following code:
struct Empty {
static constexpr int id = 0;
};
template <typename Self, typename Base = Empty> struct Compound : public Base
{
int get_id() const
{
return Self::id;
}
};
struct A : Compound<A>
{
static constexpr int id = 0xa;
};
struct B : Compound<B, A>
{
static constexpr int id = 0xb;
};
template <typename T, typename Base> int get_id(const Compound<T, Base> &c)
{
return c.get_id();
}
int test_a()
{
A var;
return get_id(var);
}
int test_b()
{
B var;
return get_id(var);
}
test_b doesn't compile with following error:
error: no matching function for call to 'get_id(B&)'
return get_id(var);
^
note: candidate: template<class T, class Base> int get_id(const Compound<T, Base>&)
template <typename T, typename Base> int get_id(const Compound<T, Base> &c)
^
note: template argument deduction/substitution failed:
note: 'const Compound<T, Base>' is an ambiguous base class of 'B'
return get_id(var);
I understand why that is. B is derived and is convertible to both Compound<B, A>
and Compound<A, Empty>
I'm wondering if it is possible to change (within context of C++14) Compound template and get_id() function such that it would return 0xa for A and 0xb for B and would work for arbitrarily long chains of inheritance.
I know that this can be easily solved with virtual function that is overridden in A and B, but I would like to avoid that if possible. Everywhere these types are used they are known and fixed at compile time so there shouldn't be a need to incur run-time overhead.
Upvotes: 0
Views: 56
Reputation: 303097
Just keep it simple:
template <class T>
auto get_id(T const& c) -> decltype(c.get_id())
{
return c.get_id();
}
You don't need c
to be some Compound
, you really just want it to have a get_id()
member function.
Upvotes: 1
Reputation: 206607
It's not clear from your post why need to go the route of Compound
in get_id
. You can simply use:
template <typename T> int get_id(T const& c)
{
return T::id;
}
Upvotes: 0