从同一模板派生的模板类

时间:2017-03-30 20:39:48

标签: c++ templates c++14

我有以下代码:

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中重写的虚函数轻松解决,但我想尽可能避免这种情况。使用这些类型的所有地方都是已知的并且在编译时修复,因此不需要产生运行时开销。

2 个答案:

答案 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;
}