Jiv*_*son 6 c++ templates boost member-functions traits
我不愿意说我无法解决这个问题,但我无法弄清楚这一点.我用Google搜索并搜索了Stack Overflow,然后空了.
问题的抽象,可能过于模糊的形式是,我如何使用traits-pattern来实例化成员函数? [更新:我在这里使用了错误的术语.它应该是"政策"而不是"特征".特征描述现有的类.策略规定了合成类.]在10多年前我写的一组多变量函数优化器的现代化过程中出现了这个问题.
优化器都通过选择远离当前最佳点("更新")的参数空间的直线路径来操作,然后在该线上找到更好的点("线搜索"),然后测试"完成" "条件,如果没有完成,迭代.
有不同的方法可以进行更新,行搜索,以及完成测试和其他事情.连连看.不同的更新公式需要不同的状态变量数据.例如,LMQN更新需要向量,BFGS更新需要矩阵.如果评估渐变很便宜,则线搜索应该这样做.如果没有,它应该只使用功能评估.某些方法需要比其他方法更精确的线搜索.这只是一些例子.
原始版本通过虚函数实例化几种组合.通过设置在运行时测试的模式位来选择某些特征.呸.使用#define定义特征并使用#ifdef和宏定义成员函数将是微不足道的.但那是二十年前的事了.让我感到困惑的是,我无法想出一种神奇的现代方式.
如果只有一个特征变化,我可以使用奇怪的重复模板模式.但我认为没有办法将其扩展到任意的特征组合.
我尝试使用boost::enable_if等等.专门的状态信息很容易.我设法完成了这些功能,但只使用了以this-pointer作为参数的非友好外部函数.我甚至从未弄清楚如何使功能成为朋友,更不用说成员功能了.编译器(VC++ 2008)总是抱怨事情不匹配.我会喊道,"SFINAE,你这个白痴!" 但是白痴可能是我.
也许标签发送是关键.我没有深入了解这一点.
当然有可能,对吗?如果是这样,最佳做法是什么?
更新:这是另一个解释它的尝试.我希望用户能够为自定义优化器填写订单(清单),例如从中文菜单中排序 - 一个来自A列,一个来自B列等.服务员,来自A列(更新者) ,我将使用Cholesky-decompositon酱更新BFGS.从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;
}
Run Code Online (Sandbox Code Playgroud)
我认为模板专业化是朝着正确方向迈出的一步。这不适用于函数,所以我切换到类。我改变了它,所以它修改了数据。我不太热衷于受保护的会员和交朋友。没有继承的受保护成员是一种味道。将其公开或提供访问器并将其设为私有。
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;
};
Run Code Online (Sandbox Code Playgroud)