如果从未使用该函数,您可以在C ++模板函数中使用未定义的类型吗?

时间:2013-12-15 21:14:11

标签: c++

我试图在两个类的对象之间创建一个转换函数(Eigen :: Vector3d和MyVector,一个Protocol Buffers消息),但是我想延迟对函数体的评估,直到引用该函数为止(此时两者都有)将定义类。)

该函数应该可以在稍后定义这两个类的文件中调用,如果从未使用该函数,它不应该导致编译错误。

我有:

#include <Eigen/Core> // defines Eigen::Vector3d

class MyVector {
  public: int set_x(int x) { x_ = x; }
  private: int x_;
}

void operator<< (MyVector &msg, const Eigen::Vector3d &vec) {
  msg.set_x(vec.x());
}

我用作:

MyVector msg;
Eigen::Vector3d vec(1, 2, 3);
msg << vec;

如果在MyVector之后定义函数,这可以正常工作,但我希望能够定义函数,使其可以包含在缺少MyVector类的翻译单元中。

我可以将功能更改为:

template<typename Msg>
void operator<< (Msg &msg, ...

但这是不可接受的,因为它适用于其他消息类:

quaternion_msg << Eigen::Vector3d(1, 2, 3);   // quaternion has xyz but also w!

我希望这会导致构建错误。

是否有某种模板魔法可以做到这一点?如果没有,是否有更好的方法来提供此操作员不将MyVector添加到头文件(或其依赖项)?

2 个答案:

答案 0 :(得分:6)

您可以在函数模板中使用未定义的类型或函数,只要它们以某种方式依赖于模板参数并在瞬时定义:在查找函数模板的指针处查找非依赖名称。在实例化时查找从属名称(假设正确实现了两阶段名称查找)。

另一方面,可能使用SFINAE来阻止使用除一小部分选定类型之外的其他类型的成功实例化:

class MyVector;
template <typename Msg>
typename std::enable_if<std::is_same<Msg, MyVector>::value>::type
operator<< (Msg& msg, Eigen::Vector3d const& vec) {
    msg.set_x(vec.x);
}

type的{​​{1}}仅在std::enable_if<F, T>F时定义(并且true默认为T)。由于void仅在std::is_same<Msg, MyVector>::valuetrue时变为Msg,因此仅在使用MyVector实例化时才会定义此运算符。另一方面,它在实例化时被定义为希望定义哪个点MyVector

但是,由于MyVector在接口中命名,因此需要声明其名称,尽管不需要定义它。如果MyVector可以专门化特征,则可以避免这种需要,在这种情况下,命名MyVector类型可以被延迟,直到它被定义并且特征是专门的。如果MyVector实际上是带有默认参数的模板,那么这样做可能很重要,因为这些参数不能被前向声明。

答案 1 :(得分:1)

创建一个专门的小模板化类,并在模板化运算符中使用它&lt;&lt;功能

即:

template <typename MSG>
struct Convertor;  // generic causes compiler error

template<>
struct Convertor<MyVector> {
  static void Convert(MyVector msg, Eigen::vector3d const& vec) {
    msg.set_x(vec.x());  
  }
};

template<typename Msg>
void operator<< (Msg &msg, const Eigen::Vector3d &vec) {
  Convertor<Msg>::Convert(msg, vec);
}

如果需要,您可以将此模式扩展为更多模板参数,并专门针对您想要的转换。