我不愿意说我搞不清楚,但我想不出来。我搜索并搜索了Stack溢出,然后空了出来。
这个问题的抽象形式,可能是过于模糊的形式是,,我如何使用特性-模式来实例化成员函数?更新:我在这里使用了错误的术语。它应该是“政策”而不是“特性”。特征描述了现有的类。政策规定合成课程。这个问题是在对我十多年前写过的一组多元函数优化器进行现代化改造时提出的。
优化器都是通过从当前最佳点( "update")通过参数空间选择一条直线路径来操作的,然后在这条线上找到一个更好的点(“行搜索”),然后测试“已完成”条件,如果不执行,则迭代。
有不同的方法来执行更新,行搜索,以及可以想象的已完成的测试和其他事情。混合火柴。不同的更新公式需要不同的状态变量数据。例如,LMQN更新需要一个向量,而BFGS更新需要一个矩阵。如果计算梯度很便宜,线搜索就应该这样做。如果没有,则应该只使用函数计算。有些方法比其他方法需要更精确的行搜索。这些只是一些例子。
原始版本通过虚拟函数实例化几个组合。某些特性是通过设置在运行时测试的模式位来选择的。糟透了。用# define 's定义特征,用#ifdef和宏定义成员函数就很简单了。但那是二十年前的事了。我想不出一种神奇的现代方式。
如果只有一个不同的特征,我可以使用奇怪的反复出现的模板模式。但我看不出有什么办法把它扩展到任意组合的特征。
我试着用boost::enable_if等来做。专门的状态信息是容易的。我成功地完成了这些函数,但只能求助于以this-pointer作为参数的非朋友外部函数。我甚至都不知道如何使这些功能成为朋友,更不用说会员功能了。编译器(VC++,2008年)总是抱怨事情不匹配。我会大叫:"SFINAE,你这个白痴!“但那个白痴可能是我。
也许标签分发是关键。我对此并没有太深的兴趣。
当然是有可能的,对吧?如果是,最佳做法是什么?
更新:这是另一次解释它的尝试。我希望用户能够为自定义优化器填写订单(清单),比如从中文菜单上订购--从A栏中订购,从B栏中订购,等等。侍者,从A栏(更新者),我会让BFGS与Cholesky分解酱更新。从B列(线搜索者),我将有三次插值线搜索,eta为0.4和rho为1e-4,请。等等..。
更新:好的,好的。这是我玩过的游戏。我不情愿地提出,因为我怀疑这是一个完全错误的方法。它在vc++ 2008下运行良好。
#include <boost/utility.hpp>
#include <boost/type_traits/integral_constant.hpp>
namespace dj {
struct CBFGS {
void bar() {printf("CBFGS::bar %d\n", data);}
CBFGS(): data(1234){}
int data;
};
template<class T>
struct is_CBFGS: boost::false_type{};
template<>
struct is_CBFGS<CBFGS>: boost::true_type{};
struct LMQN {LMQN(): data(54.321){}
void bar() {printf("LMQN::bar %lf\n", data);}
double data;
};
template<class T>
struct is_LMQN: boost::false_type{};
template<>
struct is_LMQN<LMQN> : boost::true_type{};
// "Order form"
struct default_optimizer_traits {
typedef CBFGS update_type; // Selection from column A - updaters
};
template<class traits> class Optimizer;
template<class traits>
void foo(typename boost::enable_if<is_LMQN<typename traits::update_type>,
Optimizer<traits> >::type& self)
{
printf(" LMQN %lf\n", self.data);
}
template<class traits>
void foo(typename boost::enable_if<is_CBFGS<typename traits::update_type>,
Optimizer<traits> >::type& self)
{
printf("CBFGS %d\n", self.data);
}
template<class traits = default_optimizer_traits>
class Optimizer{
friend typename traits::update_type;
//friend void dj::foo<traits>(typename Optimizer<traits> & self); // How?
public:
//void foo(void); // How???
void foo() {
dj::foo<traits>(*this);
}
void bar() {
data.bar();
}
//protected: // How?
typedef typename traits::update_type update_type;
update_type data;
};
} // namespace dj
int main() {
dj::Optimizer<> opt;
opt.foo();
opt.bar();
std::getchar();
return 0;
}发布于 2010-04-15 02:15:01
我认为模板专业化是朝着正确方向迈出的一步。这不适用于函数,所以我转到了类。我改变了它所以它修改了数据。我不太喜欢受保护的会员和交友。没有继承的受保护成员很难闻。将其公开或提供访问器,并使其私有。
template <typename>
struct foo;
template <>
struct foo<LMQN>
{
template <typename OptimizerType>
void func(OptimizerType& that)
{
printf(" LMQN %lf\n", that.data.data);
that.data.data = 3.14;
}
};
template <>
struct foo<CBFGS>
{
template <typename OptimizerType>
void func(OptimizerType& that)
{
printf(" CBFGS %lf\n", that.data.data);
}
};
template<class traits = default_optimizer_traits>
class Optimizer{
public:
typedef typename traits::update_type update_type;
void foo() {
dj::foo<typename traits::update_type>().func(*this);
}
void bar() {
data.bar();
}
update_type data;
};发布于 2010-04-15 12:17:54
一个简单的解决方案可能是只使用基于标记的转发,例如:
template<class traits>
void foo(Optimizer<traits>& self, const LMQN&) {
printf(" LMQN %lf\n", self.data.data);
}
template<class traits>
void foo(Optimizer<traits>& self, const CBFGS&) {
printf("CBFGS %d\n", self.data.data);
}
template<class traits = default_optimizer_traits>
class Optimizer {
friend class traits::update_type;
friend void dj::foo<traits>(Optimizer<traits>& self,
const typename traits::update_type&);
public:
void foo() {
dj::foo<traits>(*this, typename traits::update_type());
}
void bar() {
data.bar();
}
protected:
typedef typename traits::update_type update_type;
update_type data;
};或者,如果您想方便地根据不同的特性将几个函数组合在一起,也许是这样的:
template<class traits, class updater=typename traits::update_type>
struct OptimizerImpl;
template<class traits>
struct OptimizerImpl<traits, LMQN> {
static void foo(Optimizer<traits>& self) {
printf(" LMQN %lf\n", self.data.data);
}
};
template<class traits>
struct OptimizerImpl<traits, CBFGS> {
static void foo(Optimizer<traits>& self) {
printf("CBFGS %d\n", self.data.data);
}
};
template<class traits = default_optimizer_traits>
class Optimizer{
friend class traits::update_type;
friend struct OptimizerImpl<traits>;
public:
void foo() {
OptimizerImpl<traits>::foo(*this);
}
// ...
};发布于 2010-04-15 06:25:42
您对enable_if的使用有点奇怪。我见过它只有两种方式:
将其用于实际参数可能会造成大破坏。
不管怎么说,它绝对可以用于成员函数:
template<class traits = default_optimizer_traits>
class Optimizer{
typedef typename traits::update_type update_type;
public:
typename boost::enable_if< is_LQMN<update_type> >::type
foo()
{
// printf is unsafe, prefer the C++ way ;)
std::cout << "LQMN: " << data << std::endl;
}
typename boost::enable_if< is_CBFGS<update_type> >::type
foo()
{
std::cout << "CBFGS: " << data << std::endl;
}
private:
update_type data;
};注意,默认情况下,enable_if返回void,在大多数情况下,它非常适合作为返回类型。“参数”语法通常保留给构造函数用例,因为那时您没有一个返回类型可供使用,但通常更喜欢使用返回类型,这样它就不会干扰过载解析。
编辑
正如注释中所指出的,以前的解决方案不起作用。我无法找到使用enable_if的任何替代方法,只有“简单”重载方式:
namespace detail
{
void foo_impl(const LMQN& data)
{
std::cout << "LMQN: " << data.data << std::endl;
}
void foo_impl(const CBFGS& data)
{
std::cout << "CBFGS: " << data.data << std::endl;
}
} // namespace detail
template<class traits = default_optimizer_traits>
class Optimizer{
typedef typename traits::update_type update_type;
public:
void foo() { detail::foo_impl(data); }
private:
update_type data;
};它不是enable_if,但它在不向每个人公开Optimizer内部信息的情况下完成了任务。接吻?
https://stackoverflow.com/questions/2641367
复制相似问题