涵盖const和非const方法的C ++模板
对于复制 const
和非 const
版本的相同代码,我遇到了问题。我可以用一些代码来说明问题。这里有两个示例访问者,一个访问者修改了所访问的对象,一个没有进行访问。
I have a problem with duplication of identical code for const
and non-const
versions. I can illustrate the problem with some code. Here are two sample visitors, one which modifies the visited objects and one which does not.
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"; }
};
现在这是一个聚合对象-它只有两个数据成员,但是我的实际代码复杂得多:
Now here is an aggregate object - this has just two data members but my actual code is much more complex:
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);
}
};
以及用于演示上述内容的函数:
And a function to demonstrate the above:
static void test()
{
Aggregate a;
a(VisitorRead());
const Aggregate b(a);
b(VisitorWrite());
}
现在,这里的问题是 Aggregate的重复:: operator()
用于 const
和非 const 版本。
Now, the problem here is the duplication of Aggregate::operator()
for const
and non-const
versions.
是否可以避免重复执行此代码?
Is it somehow possible to avoid duplication of this code?
我有一个解决方案是这样:
I have one solution which is this:
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
类型的事实感到不满意。
This means neither Aggregate::operator()
is needed and there is no duplication. But I am not comfortable with the fact that visit()
is generic with no mention of type Aggregate
.
有更好的方法吗?
我倾向于简单的解决方案,所以我会选择自由函数方法,可能会添加SFINAE以禁用 Aggregate
以外的类型的功能:
I tend to like simple solutions, so I would go for the free-function approach, possibly adding SFINAE to disable the function for types other than 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);
}
其中 enable_if
, is_same
和 remove_const
实际上很容易实现,如果您没有启用C ++ 0x的编译器(或者您没有可以从boost type_traits借用它们)
Where enable_if
, is_same
and remove_const
are actually simple to implement if you don't have a C++0x enabled compiler (or you can borrow them from boost type_traits)
编辑:在编写SFINAE方法时,我意识到在提供普通模板时存在很多问题OP中没有SFINAE的解决方案,其中包括以下事实:如果您需要提供多个 visitable 类型,则不同的模板会发生冲突(即,它们与其他模板一样好) 。通过提供SFINAE,您实际上仅为满足条件的类型提供了 visit
函数,将奇怪的SFINAE转换为等效项:
EDIT: While writing the SFINAE approach I realized that there are quite a few problems in providing the plain templated (no SFINAE) solution in the OP, which include the fact that if you need to provide more than one visitable types, the different templates would collide (i.e. they would be as good a match as the others). By providing SFINAE you are actually providing the visit
function only for the types that fulfill the condition, transforming the weird SFINAE into an equivalent to:
// pseudocode, [] to mark *optional*
template <typename Visitor>
void visit( Visitor & v, Aggregate [const] & s ) {
v( s.i );
v( s.d );
}