我试图在两个类的对象之间创建一个转换函数(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添加到头文件(或其依赖项)?
答案 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>::value
为true
时变为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);
}
如果需要,您可以将此模式扩展为更多模板参数,并专门针对您想要的转换。