Как вернуть шаблонный класс из шаблонной функции? - PullRequest
1 голос
/ 25 мая 2010

Как мне сделать что-то, что заставило бы скомпилировать последнюю закомментированную строку? Как мне изменить этот код, чтобы он работал?

#include<iostream>

using namespace std;

template <int x>
class someclass{
 public:
  int size;
  int intarr[x];
  someclass():size(x){}
};

template<int x, int y>
int somefunc(someclass<x> A, someclass<y> B){
 return ( A.size > B.size ? A.size : B.size); 
}

template<int x, int y, int z>
someclass<x> anotherfunc(someclass<y> A, someclass<z> B){
 return ( A.size > B.size ? A : B); 
}

int main(){

 someclass<5> A;
 someclass<10> B;
 cout << "SIZE = " << somefunc(A,B) << endl;
 //cout << "SIZE = " << (anotherfunc(A,B)).size << endl; //THIS DOES NOT COMPILE
 return 0;
}

Ответы [ 2 ]

4 голосов
/ 25 мая 2010

Как узнать, что x находится вне функции? (Он не может заглянуть в тело, потому что в , какое тело какой функции он смотрит, зависит от того, какое значение x получает!). Также вы не можете написать это ?:, потому что обе ваши ветви дают совершенно несвязанные типы, которые не могут получить общий тип. Но этот оператор требует наличия общего типа для обеих ветвей, которые он оценивает.

И еще одна проблема, с которой вы сталкиваетесь, size не является постоянной времени компиляции, уже разработана другим постом.

Я думаю, что это должно работать:

template<int y, int z>
someclass<sizeof (char[+(y >= z)]) * y> anotherfunc(someclass<y> A, someclass<z> B){
 return A; 
}

template<int y, int z>
someclass<sizeof (char[+(y < z)]) * z> anotherfunc(someclass<y> A, someclass<z> B){
 return B; 
}

Теперь при его вызове y и z выводятся параметрами, а затем параметры подставляются в возвращаемый тип. sizeof(char[1 or 0]) проверит, больше ли y или z. В соответствующем шаблоне, который оценивает это как sizeof(char[1]) (что дает 1), мы умножим на значение, которое больше (или равно). Если соответствующий шаблон выдает sizeof(char[0]), то это ошибка вывода (массив не может быть нулевого размера!), И шаблон не будет выбран по разрешению перегрузки (известному как SFINAE ).

Унарный + дает 1 или 0 как int вместо true или false, что может вызвать предупреждения компилятора для некоторых компиляторов.


Существует также «чистый» способ с enable_if. Это не делает отвратительные sizeof трюки, а скорее использует общий установленный паттерн enable_if. Boost имеет реализацию этого

template<int y, int z>
typename boost::enable_if_c<(y >= z), someclass<y> >::type 
anotherfunc(someclass<y> A, someclass<z> B){
 return A; 
}

template<int y, int z>
typename boost::enable_if_c<(y < z), someclass<z> >::type 
anotherfunc(someclass<y> A, someclass<z> B){
 return B; 
}

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

3 голосов
/ 25 мая 2010

Помните, что в C ++ все определяется во время компиляции. В anotherfunc до времени выполнения вы не знаете, возвращаете ли вы класс "y-typed" или "z-typed". Вам нужно знать, что вы возвращаете, если собираетесь возвращать шаблонный класс из функции.

Есть некоторые приемы, которые вы можете использовать, перегружая оператор приведения промежуточного класса, чтобы получить что-то, похожее на то, что оно перегружается в типе возвращаемого значения, но это действительно злоупотребляет языком (и вам все равно нужно знать тип возвращаемого значения во время компиляции !)

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