Я не хочу говорить, что не могу понять это, но я не могу понять это. Я гуглил, искал переполнение стека и выглянул пустым.
Абстрактная и, возможно, чрезмерно расплывчатая форма вопроса: как я могу использовать шаблон признаков для создания экземпляров функций-членов? [Обновление: я использовал неправильный термин здесь. Это должны быть «политики», а не «черты». Черты описывают существующие классы. Политики предписывают синтетические классы.] Возник вопрос при модернизации набора оптимизаторов многомерных функций, который я написал более 10 лет назад.
Все оптимизаторы работают, выбирая прямой путь через пространство параметров вдали от текущей лучшей точки («обновление»), затем находя лучшую точку на этой линии («поиск линии»), затем проверяя условие «выполнено» и, если не выполнено, итерация.
Существуют разные методы для обновления, поиска строк и, возможно, для проделанного теста и других вещей. Смешивать и сочетать. Различные формулы обновления требуют разных данных о состоянии. Например, обновление LMQN требует вектора, а обновление BFGS требует матрицы. Если оценка градиентов стоит дешево, то поиск строки должен сделать это. Если нет, он должен использовать только оценки функций. Некоторые методы требуют более точного поиска строк, чем другие. Это всего лишь несколько примеров.
Исходная версия создает несколько комбинаций с помощью виртуальных функций. Некоторые характеристики выбираются путем установки битов режима, которые тестируются во время выполнения. Тьфу. Было бы тривиально определить черты с помощью # define и функций-членов с помощью # ifdef и макросов. Но это так двадцать лет назад. Меня беспокоит, что я не могу придумать современный способ.
Если бы существовала только одна изменяющаяся черта, я мог бы использовать любопытно повторяющийся шаблонный шаблон . Но я не вижу способа распространить это на произвольные комбинации черт.
Я пытался сделать это, используя boost::enable_if
и т. Д. Специализированная информация о состоянии была простой. Мне удалось выполнить функции, но только благодаря использованию внешних функций, не являющихся друзьями, которые имеют указатель this
в качестве параметра. Я даже не придумал, как сделать функции друзьями, а тем более функциями-членами. Компилятор (VC ++ 2008) всегда жаловался, что вещи не совпадают. Я бы крикнул: "СФИНА, ты, придурок!" но придурок, наверное, я.
Возможно, тэг-диспетчер является ключом. Я не очень углубился в это.
Конечно, это возможно, верно? Если так, что является лучшей практикой?
ОБНОВЛЕНИЕ: Вот еще одна попытка объяснить это. Я хочу, чтобы пользователь мог заполнить заказ (манифест) для пользовательского оптимизатора, что-то вроде заказа из китайского меню - один из столбца A, один из столбца B и т. Д. Официант, из столбца A (средства обновления) Я получу обновление BFGS с соусом Холески-декомпозитон. Из столбца B (искатели строк) у меня будет кубический интерполяционный поиск строк с eta 0,4 и относительным значением 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;
}