我遇到了 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"; }
};
现在这里是一个聚合对象——它只有两个数据成员,但我的实际代码要复杂得多:
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);
}
};
还有一个函数来演示以上内容:
static void test()
{
Aggregate a;
a(VisitorRead());
const Aggregate b(a);
b(VisitorWrite());
}
现在,这里的问题是 Aggregate::operator()
对于 const
和非 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);
}
这意味着不需要 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);
}
如果您没有启用 C++0x 的编译器(或你可以从 boost type_traits 借用它们)
编辑:在编写 SFINAE 方法时,我意识到在 OP 中提供纯模板化(无 SFINAE)解决方案存在很多问题,其中包括如果您需要提供多个 visitable 类型,不同的模板会发生冲突(即它们会和其他模板一样好)。通过提供 SFINAE,您实际上只是为满足条件的类型提供 visit
函数,将奇怪的 SFINAE 转换为等价于:
// pseudocode, [] to mark *optional*
template <typename Visitor>
void visit( Visitor & v, Aggregate [const] & s ) {
v( s.i );
v( s.d );
}
关于涵盖 const 和非 const 方法的 C++ 模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7792052/