我不愿意说我想不通,但我想不通。我用谷歌搜索并搜索了 Stack Overflow,但结果是空的。
问题的抽象且可能过于模糊的形式是,如何使用特征模式来实例化成员函数? [更新:我在这里使用了错误的术语。它应该是“政策”而不是“特征”。特征描述现有的类。策略规定了合成类。]这个问题是在对我 10 多年前编写的一组多元函数优化器进行现代化改造时提出的。
优化器都通过选择一条远离当前最佳点的直线路径通过参数空间(“更新”),然后在该线上找到更好的点(“线搜索”),然后测试“完成” " 条件,如果没有完成,则迭代。
有不同的方法来进行更新、行搜索,以及可以想象的完成测试和其他事情。连连看。不同的更新公式需要不同的状态变量数据。例如,LMQN 更新需要一个向量,而 BFGS 更新需要一个矩阵。如果评估梯度很便宜,那么线搜索应该这样做。如果没有,它应该只使用函数评估。有些方法比其他方法需要更准确的线搜索。这些只是一些例子。
原始版本通过虚函数实例化了几种组合。通过设置在运行时测试的模式位来选择一些特征。呸。用#define 定义特征并用#ifdef 和宏定义成员函数将是微不足道的。但那是二十年前的事了。让我感到困扰的是,我无法找到一种非常棒的现代方式。
如果只有一个不同的特征,我可以使用奇怪的重复模板模式。但我认为没有办法将其扩展到任意特征组合。
我尝试使用boost::enable_if
等。专业的状态信息很容易。我设法完成了这些功能,但只能求助于将this
-pointer 作为参数的非友元外部函数。我什至从未想过如何让函数成为朋友,更不用说成员函数了。编译器(VC++ 2008)总是抱怨事情不匹配。我会大喊:“SFINAE,你这个白痴!” 但这个白痴可能是我。
也许标签调度是关键。我还没有深入了解。
当然有可能,对吧?如果是这样,最佳做法是什么?
更新:这是另一个解释它的尝试。我希望用户能够为自定义优化器填写订单(清单),例如从中文菜单中订购 - 一个来自 A 列,一个来自 B 列,等等。服务员,来自 A 列(更新程序) ,我将使用 Cholesky 分解酱更新 BFGS。请从 B 列(线搜索器)开始,我将进行三次插值线搜索,其 eta 为 0.4,rho 为 1e-4。ETC...
更新:好的,好的。这是我做过的游戏。我不情愿地提供它,因为我怀疑这是一种完全错误的方法。它在 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;
}