Функции членства класса инстанцируют черты [политик, на самом деле]

Я отказываюсь сказать, что я не могу понять это, но я не могу понять это. Я погуглил и искал Переполнение стека и подошел пустой.

Краткий обзор, и возможно чрезмерно неопределенная форма вопроса, как я могу использовать шаблон черт для инстанцирования функций членства? [Обновление: Я использовал неправильный термин здесь. Это должны быть "политики", а не "черты". Черты описывают существующие классы. Политики предписывают синтетические классы.] Вопрос подошел при модернизации ряда многомерных функциональных оптимизаторов, которые я записал больше чем 10 лет назад.

Оптимизаторы все действуют путем выбора прямолинейного пути через пространство параметров далеко от текущей лучшей точки ("обновление"), затем нахождения лучшей точки на той строке ("поиск строки"), затем тестирования на "сделанное" условие, и если не сделанный, выполняя итерации.

Существуют различные методы для того, чтобы сделать обновление, поиск строки, и очевидно для сделанного теста и других вещей. Смешивание и подгонка. Различные формулы обновления требуют различных данных переменной состояния. Например, обновление LMQN требует вектора, и обновление BFGS требует матрицы. Если оценка градиентов является дешевой, поиск строки должен сделать так. В противном случае это должно использовать функциональные оценки только. Некоторые методы требуют более точных поисков строки, чем другие. Это - просто некоторые примеры.

Исходная версия инстанцирует нескольких из комбинаций посредством виртуальных функций. Некоторые черты выбраны путем установки битов режима, которые тестируются во времени выполнения.Фу. Это было бы тривиально для определения черт с #define и функций членства с #ifdef и макросы. Но это так двадцать лет назад. Это прослушивает меня, что я не могу выяснить удар свиста современный путь.

Если бы была только одна черта, которая варьировалась, то я мог использовать любопытно повторяющийся шаблонный шаблон. Но я не вижу способа расширить это до произвольных комбинаций черт.

Я пытался делать его использование boost::enable_if, и т.д. Специализированная информация состояния была легка. Мне удалось сделать функции, но только путем обращения к недругу внешних функций, которые имеют this- указатель в качестве параметра. Я даже не выяснил, как завести друзей функций, а тем более функции членства. Компилятор (VC ++ 2008) всегда жаловался, что вещи не соответствовали. Я вопил бы, "SFINAE, Вы идиот!" но идиот - вероятно, я.

Возможно, отправка тега является ключом. Я не добрался очень глубоко в это.

Конечно, это возможно, правильно? Если так, что такое лучшая практика?

ОБНОВЛЕНИЕ: вот другая попытка при объяснении его. Я хочу, чтобы пользователь смог заполнить порядок (декларация) для пользовательского оптимизатора, чего-то как удаление китайского меню - один из столбца A, один из столбца B, и т.д. Официант, из столбца A (updaters), у меня будет обновление BFGS с соусом Cholesky-decompositon. Из столбца B (искатели строки) у меня будет поиск строки кубичной интерполяции с ЭТА 0,4 и ро 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;
}
6
задан Jive Dadson 16 April 2010 в 01:11
поделиться

5 ответов

Я считаю, что специализация шаблонов - это шаг в правильном направлении. Это не работает с функциями, поэтому я переключился на классы. Я изменил его так, чтобы он изменял данные. Я не очень продан в защищенных членах и в друзьях. Защищенные члены без наследования - это запах. Сделайте его общедоступным или предоставьте средства доступа и сделайте его частным.

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;
};
1
ответ дан 17 December 2019 в 07:02
поделиться

Было бы тривиально определить черты с # define и функциями-членами с # ifdef и макросами. Но это было так двадцать лет назад.

Хотя, возможно, стоит изучить новые методы, макросы часто являются самым простым способом делать что-то, и их не следует отбрасывать как инструмент только потому, что они «старые». Если вы посмотрите на MPL in boost и книгу по TMP, вы найдете много использования препроцессора.

1
ответ дан 17 December 2019 в 07:02
поделиться

Вы используете 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 каждому. KISS?

0
ответ дан 17 December 2019 в 07:02
поделиться

Вот что придумал я (ОП). Можете ли вы сделать его круче?

Основной класс шаблона оптимизатора наследует классы реализации политики. Это дает этим классам доступ к необходимым им защищенным членам оптимизатора. Другой класс шаблона оптимизатора разделяет манифест на составные части и создает экземпляр основного шаблона оптимизатора.

#include <iostream>
#include <cstdio>

using std::cout;
using std::endl;

namespace dj {

// An updater.
struct CBFGS {
    CBFGS(int &protect_)
        : protect(protect_)
    {}

    void update () {
        cout << "CBFGS " << protect << endl;
    }   

    // Peek at optimizer's protected data
    int &protect;

};

// Another updater
struct LMQN {
    LMQN(int &protect_)
        : protect(protect_)
    {}

    void update () {
        cout << "LMQN " << protect << endl;
    }

    // Peek at optimizer's protected data
    int &protect;

};

// A line-searcher
struct cubic_line_search {
    cubic_line_search (int &protect2_)
        : protect2(protect2_)
    {}

    void line_search() {
        cout << "cubic_line_search  " << protect2 << endl;
    }   

    // Peek at optimizer's protected data
    int &protect2;

};

struct default_search_policies {
    typedef CBFGS update_type;
    typedef cubic_line_search line_search_type;
};

template<class Update, class LineSearch>
class Opt_base: Update, LineSearch
{
public:
    Opt_base()
        : protect(987654321) 
        , protect2(123456789)
        , Update(protect)
        , LineSearch(protect2)
    {}
    void minimize() {
        update();
        line_search();
    }

protected:
    int protect;
    int protect2;
};

template<class Search_Policies=default_search_policies>
class Optimizer: 
    public Opt_base<typename Search_Policies::update_type
                  , typename Search_Policies::line_search_type
                    >
{};

} // namespace dj



int main() {
    dj::Optimizer<> opt; // Use default search policies
    opt.minimize();

    struct my_search_policies {
        typedef dj::LMQN update_type;
        typedef dj::cubic_line_search line_search_type;
    };

    dj::Optimizer<my_search_policies> opt2;
    opt2.minimize();

    std::getchar();
    return 0;
}
0
ответ дан 17 December 2019 в 07:02
поделиться

Простым решением может быть использование пересылки на основе тегов, например что-то вроде этого:

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);
    }
    // ...
};
2
ответ дан 17 December 2019 в 07:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: