Как уменьшить аргументы шаблона? - PullRequest
7 голосов
/ 19 ноября 2009

Здесь у меня есть функтор следующего вида:

template<class T, class Foo, T Foo::*p>
struct X {
    void operator()(Foo & f) {
        (f.*p) = 12 * (f.*p);   // simple example. could be more complex `operator()`
    }

};

И образец структуры:

struct FF
{
    int m;
    int r;
};

Я хочу использовать функтор X, но я не хочу явно указывать аргумент шаблона следующим образом:

void testforx()
{
    std::vector<FF> cont(5);
    std::for_each(cont.begin(), cont.end(), X<int, FF, &FF::r>() );  // it work, but I don't want to write `int` and `FF`
    std::for_each(cont.begin(), cont.end(), createx<&FF::r>() );     // how I would like to use it, how to declare `createx` function?
}

Вот что я пытался безуспешно:

// that is what I tried, but it could not deduce T and Foo
template<T Foo::*p, class T, class Foo>
X<T, Foo, T Foo::*p> createx()
{
    return X<T, Foo, p>();
}

// this works, but requires to write T and Foo explicitly
template<class T, class Foo, T Foo::*p>
X<T, Foo, T Foo::*p> createx()
{
    return X<T, Foo, p>();
}

Ответы [ 3 ]

8 голосов
/ 19 ноября 2009

Я бы не стал хранить указатель на член в качестве аргумента шаблона:

template<class T, class Foo>
struct X {
    X(T Foo::*p): p(p) {}
    void operator()(Foo & f) {
        (f.*p) = 12 * (f.*p);   // simple example. could be more complex `operator()`
    }
private:
    T Foo::*p;
};

template <class T, class Foo>
X<T, Foo> MakeX(T Foo::*p)
{
    return p;
}

Я не думаю, что можно вывести типы с помощью вашего подхода: вы не можете использовать указатель на член, переданный функции, в которой происходит выведение типа.

Edit: Хотя могут быть решения на основе макросов.

Например, вы можете создать класс для создания экземпляров X, например:

template <class T, class Foo>
struct XMaker
{
    template <T Foo::*p>
    X<T, Foo, p> make() { return X<T, Foo, p>(); }
};

Теперь вы можете создать функцию make ... для вывода T и Foo:

template <class T, class Foo>
XMaker<T, Foo> make_x_maker(T Foo::*)
{
    return XMaker<T, Foo>();
}

Что позволяет написать макрос наподобие

#define CREATE_X(member) make_x_maker(member).make<member>()

Использование:

std::for_each(cont.begin(), cont.end(), CREATE_X(&FF::r) );
1 голос
/ 19 ноября 2009

У меня был бы один вопрос: вам действительно нужно указать все эти аргументы?

struct XR
{
  template <class Foo>
  void operator()(Foo& foo) const { foo.r = 12 * foo.r; }
};

Это работает, нет необходимости в дополнительном make методе, он просто работает:

void testforx()
{
  std::vector<FF> cont(5);
  std::for_each(cont.begin(), cont.end(), XR()); 
}

Я предпочитаю не быть СЛИШКОМ универсальным при создании шаблонов.

Если вам нужен более сложный operator(), вы всегда можете сделать тяжелую работу ВНУТРИ.

Также вы можете рассмотреть Boost.Bind, если вы действительно хотите извлечь функции указателя и ссылки на атрибуты.

EDIT

У меня есть идея, которая будет немного отличаться и не потребует никакой магии макросов или даже магии метапрограммирования.

Почему бы просто не использовать typedef и покончить с этим?

Ладно, может быть не так автоматизировано, как хотелось бы ... но вам нужно всего лишь набрать это один раз.

typedef X<int,FF,&FF::m> X_FF_m; // once

std::for_each(cont.begin(), cont.end(), X_FF_m() );

Кажется, меньше печатать, чем

std::for_each(cont.begin(), cont.end(), createX<&FF::m>());

повторяется снова и снова.

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

1 голос
/ 19 ноября 2009

Я не думаю, что возможно уменьшить количество аргументов шаблона, которые вы должны указать, если хотите, чтобы указатель на функцию-член произвольного типа был аргументом шаблона.

Вместо указателей на функции-члены вы можете использовать параметр обычного типа для функтора, который извлекает ссылку:

template<typename Func>
class X
{
public:
    explicit X(Func f = Func()) : f(f) {}

    template<class K>
    void operator()(K & k) const {
       f(k) = 12 * f(k);
    }
private:
    Func f;
};

Тогда у вас все еще есть возможность использовать специальный функтор, который напрямую обращается к определенному члену (если вы считаете, что это обеспечивает лучшую производительность), или использовать более общий функтор доступа, который делает это с указателем на функцию-член в качестве члена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...