pap*_*jam 16 c++ templates visitor
我有重复相同代码const和非const版本的问题.我可以用一些代码来说明问题.这里有两个样本访问者,一个修改访问对象,另一个不访问.
struct VisitorRead
{
template <class T>
void operator()(T &t) { std::cin >> t; }
};
struct VisitorWrite
{
template <class T>
void operator()(const T &t) { std::cout << t << "\n"; }
};
Run Code Online (Sandbox Code Playgroud)
现在这里是一个聚合对象 - 这只有两个数据成员,但我的实际代码要复杂得多:
struct Aggregate
{
int i;
double d;
template <class Visitor>
void operator()(Visitor &v)
{
v(i);
v(d);
}
template <class Visitor>
void operator()(Visitor &v) const
{
v(i);
v(d);
}
};
Run Code Online (Sandbox Code Playgroud)
并且有一个函数来演示以上内容:
static void test()
{
Aggregate a;
a(VisitorRead());
const Aggregate b(a);
b(VisitorWrite());
}
Run Code Online (Sandbox Code Playgroud)
现在,这里的问题是Aggregate::operator()for const和non const版本的重复.
是否有可能避免重复此代码?
我有一个解决方案是这样的:
template <class Visitor, class Struct>
void visit(Visitor &v, Struct &s)
{
v(s.i);
v(s.i);
}
static void test2()
{
Aggregate a;
visit(VisitorRead(), a);
const Aggregate b(a);
visit(VisitorWrite(), b);
}
Run Code Online (Sandbox Code Playgroud)
这意味着既不Aggregate::operator()需要也不重复.但我不满意visit()没有提及类型的通用事实Aggregate.
有没有更好的办法?
我倾向于喜欢简单的解决方案,所以我会选择自由函数方法,可能会添加 SFINAE 来禁用除以下类型之外的函数Aggregate:
template <typename Visitor, typename T>
typename std::enable_if< std::is_same<Aggregate,
typename std::remove_const<T>::type
>::value
>::type
visit( Visitor & v, T & s ) { // T can only be Aggregate or Aggregate const
v(s.i);
v(s.d);
}
Run Code Online (Sandbox Code Playgroud)
Where enable_if,is_same并且remove_const如果您没有启用 C++0x 的编译器(或者您可以从 boost type_traits 借用它们),则实际上很容易实现
编辑:在编写 SFINAE 方法时,我意识到在 OP 中提供简单模板化(无 SFINAE)解决方案存在很多问题,其中包括如果您需要提供多个可访问类型,不同的模板将碰撞(即他们会和其他人一样匹配)。通过提供 SFINAE,您实际上visit只为满足条件的类型提供函数,将奇怪的 SFINAE 转换为等效于:
// pseudocode, [] to mark *optional*
template <typename Visitor>
void visit( Visitor & v, Aggregate [const] & s ) {
v( s.i );
v( s.d );
}
Run Code Online (Sandbox Code Playgroud)
struct Aggregate
{
int i;
double d;
template <class Visitor>
void operator()(Visitor &v)
{
visit(this, v);
}
template <class Visitor>
void operator()(Visitor &v) const
{
visit(this, v);
}
private:
template<typename ThisType, typename Visitor>
static void visit(ThisType *self, Visitor &v) {
v(self->i);
v(self->d);
}
};
Run Code Online (Sandbox Code Playgroud)
好的,所以仍然有一些样板,但没有重复的代码依赖于Aggregate的实际成员.与const_cast(例如)Scott Meyers倡导的避免重复的方法不同,编译器将确保两个公共函数的const正确性.