我有以下代码:
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无法编译并出现以下错误:
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);
我明白为什么会这样。 B是派生的,可以转换为Compound<B, A>
和Compound<A, Empty>
我想知道是否有可能改变(在C ++ 14的上下文中)复合模板和get_id()函数,使得它将为A返回0xa,为B返回0xb,并且可以用于任意长的继承链
我知道这可以通过在A和B中重写的虚函数轻松解决,但我想尽可能避免这种情况。使用这些类型的所有地方都是已知的并且在编译时修复,因此不需要产生运行时开销。
答案 0 :(得分:1)
保持简单:
template <class T>
auto get_id(T const& c) -> decltype(c.get_id())
{
return c.get_id();
}
您不需要 c
成为某个Compound
,您真的只希望它拥有get_id()
成员函数。
答案 1 :(得分:0)
从您的帖子中不清楚为什么需要走Compound
get_id
的路线。你可以简单地使用:
template <typename T> int get_id(T const& c)
{
return T::id;
}