параметр функции шаблона шаблона

На всю жизнь я не могу заставить работать эту простую часть тайной магии шаблонов:

template<typename T, int a, int b>
int f(T v){
  return v*a-b; // just do something for example
}

template<typename T, int a, int b, template<typename,int,int> class func>
class C{
  int f(){
    return func<T,a,b>(3);
  }
};

int main(){
  C<float,3,2, f> c;
}

Можно ли это сделать без привлечения функторов?


person Emily L.    schedule 01.08.2013    source источник
comment
Чего именно вы пытаетесь достичь?   -  person nijansen    schedule 01.08.2013
comment
мой компилятор разбился при выполнении этого кода.   -  person Saksham    schedule 01.08.2013
comment
@nijansen разве MSVS2010 не стабилен ??   -  person Saksham    schedule 01.08.2013
comment
@Сакшам Нет, нет, нет. Просто нет.   -  person nijansen    schedule 01.08.2013
comment
не обманывайтесь, он достаточно стабилен. Как всегда проблема в коде   -  person stijn    schedule 01.08.2013
comment
@nijansen просто упрощает некоторые модульные тесты для устаревшего кода. Я не могу перейти на функторы, так как это слишком много работы в кодовой базе.   -  person Emily L.    schedule 01.08.2013


Ответы (4)


f должен быть классом — у вас есть функция.

Смотри ниже:

// Class acts like a function - also known as functor.
template<typename T, int a, int b>
class f
{
  int operator()(T v)
  {
    return v*a-b; // just do something for example
  }
};

template<typename T, int a, int b, template<typename,int,int> class func>
class C
{
  int f()
  {
    return func<T,a,b>(3);
  }
};

int main()
{
  C<float,3,2, f> c;
}

... И адаптированная версия, если вам нужно портировать устаревший код (адаптирует функцию к шаблону класса):

#include <iostream>


template<typename T, int a, int b>
int f(T v)
{
  std::cout << "Called" << std::endl;
  return v*a-b; // just do something for example
}

template<typename T, int a, int b, template<typename,int,int> class func>
struct C
{
  int f()
  {
    return func<T,a,b>(3);
  }
};

template <class T, int a, int b>
struct FuncAdapt
{
  T x_;
  template <class U>
  FuncAdapt( U x )
  : x_( x )
  {}
  operator int() const
  {
    return f<T,a,b>( x_ );
  }
};

int main()
{
  C<float,3,2, FuncAdapt > c;
  c.f();
}
person Werner Erasmus    schedule 01.08.2013
comment
поздравляю с первыми баллами - person Saksham; 01.08.2013
comment
Спасибо. Я вижу, мне нужна репутация, чтобы проголосовать за кого-то... Поэтому я ответил на вопрос. - person Werner Erasmus; 01.08.2013
comment
Разве ОП не хотел этого без использования функторов? (quote: Можно ли это сделать без привлечения функторов?) - person mr_georg; 01.08.2013
comment
Я специально заявил, что не хочу использовать функтор. Я не могу изменить подпись или синтаксис вызова f. - person Emily L.; 01.08.2013
comment
Как насчет того, чтобы написать адаптер, который адаптирует f к заданному функтору. - person Werner Erasmus; 01.08.2013
comment
Извиняюсь за код, который не скомпилировался. Я никогда не вызывал f в своем тесте. Теперь он компилируется. Адаптер должен иметь конструктор для приема T и оператор преобразования для возвращаемого значения. - person Werner Erasmus; 01.08.2013
comment
Я принял этот ответ, так как он был ближе всего к тому, что я хотел. Однако я считаю, что существует вероятность того, что класс адаптера можно сделать более общим для упрощения синтаксиса. У меня просто нет времени разбираться :) - person Emily L.; 14.08.2013

Вы можете решить это с помощью небольшой хитрости:

template<typename T, int a, int b>
int f(T v){
  return v*a-b; // just do something for example
}

template<typename T, int, int>
using func_t = int (*)(T);

template<typename T, int a, int b, func_t<T, a, b> func>
class C{
  int f(){
    return func(3);
  }
};

C<float,3,2, f<float, 3, 2>> c;

Сначала вам нужен псевдоним типа для функции (func_t выше), и вам, к сожалению, нужно продублировать аргументы шаблона в объявлении c.

person Some programmer dude    schedule 01.08.2013
comment
... в C++11, если ваш компилятор поддерживает псевдонимы шаблонов. MSVC 2013 по-прежнему не - person SteveLove; 01.08.2013
comment
Я хотел избежать дублирования аргументов шаблона, это должно избавить меня от большого количества ввода/копирования в моих модульных тестах. Помимо этого, это лучший ответ на данный момент. - person Emily L.; 01.08.2013

Причина, по которой ваш компилятор жалуется, заключается в том, что вы передаете функцию (f) как класс последнему параметру шаблона для класса C.

Поскольку вы не можете передать функцию в качестве параметра шаблона, вы должны использовать указатели на функции или функторы. И функторы, безусловно, являются более чистым способом сделать это.

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

Если вы хотите использовать указатели функций, вы увидите что-то вроде этого:

template<typename T, int a, int b, int (*func)(T)>
class C{
    int f(){
        return (*func)(3);
    }
};

int main(){
    C< float,3,2,&f<float,3,2> > c;
}

В этом случае я не думаю, что вы сможете устранить дублирование кода в объявлении c, но я могу ошибаться.

person JSQuareD    schedule 01.08.2013

Нет, это не так. Даже синтаксис:

template <typename T, int a, int b, template <typename, int, int> class func>
                                                                  ^^^^^

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

person Angew is no longer proud of SO    schedule 01.08.2013
comment
Да, я знаю, я искал какую-то хитрость, чтобы избежать изменения моего производственного кода, чтобы сделать код модульного тестирования более аккуратным. - person Emily L.; 01.08.2013