我正在尝试使用可变参数模板为函数实现装饰器。并尝试最小化重载次数,因为它减少了模板参数deducion失败时编译器错误消息的大小。我有实现,它适用于任何类的任何成员(使用委托Ret(Ctx :: *成员)(Args ...))和一个额外的重载,它不会将指针指向成员函数,只调用第一个版本传递& CTX :: opeator()。我试图通过在这里添加成员指针参数的默认值来删除额外的重载。这是编译的版本:
template<
typename Decorator,
typename Ctx, typename R, typename... Args,
typename... CTorArgs
>
Decorator decorate(
CTorArgs&&...cargs,
const Ctx &obj, R (Ctx::*member)(Args...) const = &Ctx::operator()
) {
return Decorator(
std::function<R(Args...)>([&obj, member](Args... args){
return (obj.*member)(args...);
}),
std::forward(cargs)...
);
}
但是没有明确的成员函数规范就无法调用它。这是我现在正在玩的一个例子:
struct IntDecorator {
IntDecorator(std::function<std::string(std::string)> func):
m_func(func) {}
std::string operator() (int val) {
std::ostringstream oss;
oss << val;
return m_func(oss.str());
}
private:
std::function<std::string(std::string)> m_func;
};
struct PrefixAdder {
PrefixAdder(std::string prefix): m_prefix(prefix) {}
std::string addPrefix(std::string val) const {return m_prefix + val;}
std::string operator() (std::string val) const {return m_prefix + val;}
private:
std::string m_prefix;
};
int main(int, char**) {
PrefixAdder p("+++> ");
std::cout << decorate<IntDecorator>(p, &PrefixAdder::addPrefix)(123) << std::endl;
std::cout << decorate<IntDecorator>(p, &PrefixAdder::operator())(123) << std::endl;
std::cout << decorate<IntDecorator>(p)(123) << std::endl; // compilation error
}
编译器不能推导出类型R(成员函数返回类型)。代码在添加额外的重载后工作,我试图消除或通过指定所有模板参数甚至比额外的重载更糟糕:
template<typename Decorator, typename Ctx, typename... CTorArgs>
Decorator decorate(CTorArgs&&...cargs, const Ctx &obj) {
return decorate<Decorator>(cargs..., obj, &Ctx::operator());
}
如果没有附加版本的装饰模板,我可以自动减少类型吗?在C ++ 11中自动推断类型有什么问题?
编辑:我最初的目标是获得更好的错误消息,并且我已经使用类型特征和static_assert实现了它。所以这个问题现在更具理论性和实用性。如果有人知道如何编写一个涵盖委托和仿函数的实现,你可以提供答案,我会接受它。