假设我有一个结构(在现实生活中,那是一个自动机):
struct automaton
{
bool get_final() const { return final; }
void set_final() { final = true; }
bool final = false;
};
我想提供一个视图,它可以转换(低,反转或镜像)。因为我不仅仅有一个automaton
类,我有一个包装我的自动机的类模板(我真的想要组合,而不是继承),并将所有函数调用反弹到包装的自动机,反转需要的东西。为简单起见,这里只是转发呼叫。
手工,我会得到
template <typename Aut>
struct transposed_by_hand
{
Aut& aut;
auto get_final() const -> bool
{
return aut.get_final();
}
auto set_final() -> void
{
aut.set_final();
}
};
但是有很多功能,我不想在包装器中硬编码这么多信息(函数签名)。由于可变参数模板和传入参数的完美转发,以及decltype
的结果,很容易让一个宏来计算所有const成员函数的定义,另一个宏用于非const成员函数(差异恰恰是const
)。基本上,在这种情况下,它归结为:
template <typename Aut>
struct transposed_with_decltype
{
Aut& aut;
auto get_final() const -> decltype(aut.get_final())
{
return aut.get_final();
}
auto set_final() -> decltype(aut.set_final())
{
aut.set_final();
}
};
这适用于非const自动机,但如果我包装一个const自动机,则会中断:
int main()
{
const automaton aut;
transposed_by_hand<const automaton> trh = { aut };
transposed_with_decltype<const automaton> trd = { aut };
}
我的编译器抱怨(G ++ 4.9):
f.cc: In instantiation of 'struct transposed_with_decltype<const automaton>':
f.cc:44:49: required from here
f.cc:34:12: error: passing 'const automaton' as 'this' argument of 'void automaton::set_final()' discards qualifiers [-fpermissive]
auto set_final() -> decltype(aut.set_final())
^
和(Clang ++ 3.3):
f.cc:42:23: error: default initialization of an object of const type 'const automaton' requires a user-provided default constructor
const automaton aut;
^
f.cc:34:36: error: member function 'set_final' not viable: 'this' argument has type 'const automaton', but function is not marked const
auto set_final() -> decltype(aut.set_final())
^~~
f.cc:44:49: note: in instantiation of template class 'transposed_with_decltype<const automaton>' requested here
transposed_with_decltype<const automaton> trd = { aut };
^
f.cc:6:12: note: 'set_final' declared here
void set_final() { final = true; }
^
2 errors generated.
他们是对的! decltype
中的表达式打破了包装自动机的常量。但是,我发誓,我不打算使用这个功能。就像我不会使用相应的手工包装一样。
所以我的问题是:是否有办法编写包装set_final
的定义,以便我不必拼出其签名(输入和输出)?我曾尝试使用std::enable_if
,但这里没有改变任何问题。无论如何,它需要编译器是惰性的,并且如果它不需要,则接受不评估std::enable_if
的第二个参数...
template <typename Aut>
struct transposed_with_decltype
{
Aut& aut;
auto get_final() const -> decltype(aut.get_final())
{
return aut.get_final();
}
auto set_final() -> typename std::enable_if<!std::is_const<Aut>::value,
decltype(aut.set_final())>::type
{
aut.set_final();
}
};
提前致谢。
答案 0 :(得分:0)
我可以通过使用Xeo在评论中提到的建议来使用它(使用GCC 4.6)。也就是说,我将函数转换为一个简单的模板,如下所示:
template<typename = void>
auto set_final() -> decltype(aut.set_final()) {
return aut.set_final();
}
==编辑==
Luc Danton在下面评论说,最近的GCC可能会拒绝该代码,并抱怨decltype
不依赖。我这里只有4.6,但也许这可以解决这个问题:
template<typename KLUDGE = int>
auto set_final() -> decltype((&aut+KLUDGE(0))->set_final()) {
return aut.set_final();
}
因人而异。