2016-08-21 3 views
3

То, что я хотел бы сделать это, чтобы иметь возможность иметь различные объявления одного и того же класса шаблона, на основе значения параметра, например:шаблона перегрузки на основе значения параметра

// Enable if X == 2 
template <int X, int W, typename Y, 
      typename A = int, typename B = int> struct Z {}; 

// Enable if X != 2 
template <int X,  typename Y, 
      typename A = int, typename B = int> struct Z {}; 

я мог начать с чем-то вроде этого:

template <int X, int W, typename Y, typename A = int, typename B = int, 
      typename = std::enable_if_t<X == 2>> struct Z {}; 
template <int X,  typename Y, typename A = int, typename B = int, 
      typename = std::enable_if_t<X != 2>> struct Z {}; 

Проблема с ним в том, что, по понятным причинам, говорит о том, что он был вновь объявлен с разным числом параметров.

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

template <typename... Args> struct Z {}; 
template <int X, int W, typename Y, 
      typename A = int typename B = int> struct Z<X, W, Y> {}; 

тип/несовпадение значение -> Ожидается, тип, получил 'X/W'

Кто-нибудь есть решение для этого?

EDIT

К сожалению я не упоминал ранее, но, к сожалению, я не могу изменить порядок параметров, так как другие параметры после Y имеют значения по умолчанию.

+1

Это звучит как проблема XY. Чего вы хотите добиться именно? – skypjack

ответ

2

Вы сказали, что вы хотите сделать, как ваши комментарии здесь говорит:

// Enable if X == 2 
template <int X, int W, typename Y, typename A=int, typename B=int> 
struct Z {}; 

// Enable if X != 2 
template <int X,  typename Y, typename A=int, typename B=int> 
struct Z {}; 

Судя по всему, вы хотите обойтись без второго параметра шаблона при X !=2. Вы можете определить его без имени.

Частичная специализация может использоваться, чтобы сделать выбор:

// PRIMARY TEMPLATE: Used if X != 2 
template <int X, int, typename Y, typename A=int, typename B=int> 
       //^^ see here 
struct Z {}; 

// PARTIAL SPECIALIZATION: Used if X == 2 
template <int W, typename Y, typename A, typename B> 
struct Z<2, W, Y, A, B> {}; 

EDIT 1 из 2:(как на ваш комментарий)

Я хочу быть способный использовать структуру Z только с двумя параметрами (if X!=2): Z<3, int>

Вам придется изменить порядок шаблоны и использовать параметры по умолчанию в основной шаблон

// PRIMARY TEMPLATE: Used if X != 2 
template <int X, typename Y, int=0, typename A=int, typename B=int> 
          //^^ see here 
struct Z {}; 

// PARTIAL SPECIALIZATION: Used if X == 2 
template <typename Y, int W, typename A, typename B> 
struct Z<2, Y, W> {}; 

Вы можете использовать как:

Z<2, int> z; 
Z<3, int, 5> z3; 

EDIT 2 из 2:(на ваш вопрос Редактировать и оставлять комментарии)

Перефразируя вас:

Я хочу быть в состоянии сделать Z<3, int> без переназначения моего шаблона Parameters

Вы можете только сделать что-то вроде Z<3, int> или Z<2, int, ...>, если второй параметр шаблона является типи Остальные параметры: по умолчанию. К сожалению, это не ваше дело. Итак, вы здесь в тупике, если это действительно ваша проблема.

+0

Проверьте свой код, у вас неправильное количество аргументов шаблона. – Nelfeal

+0

@ Nelxiost, я исправил его. – WhiZTiM

+1

Ничего, не знал, что вы не можете назвать параметр. Но тем не менее, это не решает проблему, потому что я хочу иметь возможность использовать структуру Z только с двумя параметрами (если 'X! = 2'):' Z <3, int> 'дает ошибку. Я должен был бы дать что-то, чтобы его выбросили. – gmardau

0

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

// Chosen if X != 2 
template<int X, typename Y, typename A = int, typename B = int, int = 0> 
struct Z {}; // W is discarded 

// Chosen if X == 2 
template<typename Y, typename A, typename B, int W> 
struct Z<2, Y, A, B, W> {}; 

Live example

+0

Как я уже сказал в другом ответе, это не решает проблему, потому что я хочу иметь возможность использовать структуру Z только с двумя параметрами (если 'X! = 2'):' Z <3, int> 'дает ошибку. Я должен был бы дать что-то, чтобы его выбросили. – gmardau

+0

@Mehlins Отредактировано. Используя значения по умолчанию, вы можете писать такие вещи, как 'Z <3, int>'. Вам нужно только изменить порядок параметров, чтобы в конце появлялись по умолчанию. – Nelfeal

+0

Да, я тоже это заметил, и жаль, что я не упомянул об этом в сообщении, но это всего лишь образец реальной структуры, которая более длинная и сложная, и, к сожалению, я не могу изменить порядок вещей. В моем случае «Y» и еще большее количество параметров имеют значения по умолчанию. – gmardau

1

Если вы можете использовать C++ 14, и вы можете признать, что ваши intergers обернуты в std::integer_sequence, вы можете определить две версии Z таким образом

#include <iostream> 
#include <utility> 

template <typename, typename> 
struct Z; 

template <int W, typename T> 
struct Z<std::integer_sequence<int, W>, T> 
{ static constexpr int c { 0 }; }; 

template <int X, typename T> 
struct Z<std::integer_sequence<int, 2, X>, T> 
{ static constexpr int c { 2 }; }; 

int main() 
{ 
    Z<std::integer_sequence<int, 0>, long>  z0; 
    Z<std::integer_sequence<int, 2, 7>, long> z2; 
    Z<std::integer_sequence<int, 2>, long>  zX; // unacceptable ? 

    std::cout << "z0: " << z0.c << std::endl; // output: z0: 0 
    std::cout << "z2: " << z2.c << std::endl; // output: z2: 2 
    std::cout << "zX: " << zX.c << std::endl; // output: zX: 0 
} 

Я не знаю, как избежать определение, как zX с X == 2 и без W, но, если вы хотите, что zX работает как z2, вы можете определить Z следующим образом

template <typename, typename> 
struct Z; 

template <typename T, int ... I> 
struct Z<std::integer_sequence<int, I ...>, T> 
{ static constexpr int c { 0 }; }; 

template <typename T, int ... I> 
struct Z<std::integer_sequence<int, 2, I ...>, T> 
{ static constexpr int c { 2 }; }; 

и zX возвращения 2.

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

Z<std::integer_sequence<int, 0, 5, 6, 7>, long>  z0; 

--- EDIT ---

Извините, но я идиот.

Это просто исключить определение zX.

В обоих случаях вы можете объявить (но не определить) следующую специализацию.

template <typename T> 
struct Z<std::integer_sequence<int, 2>, T>; 
1

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

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

template <int X, typename Y, typename A = int, typename B = int> 
struct Z { 
    constexpr Z() {} 
}; 

template <typename Y, typename A, typename B> 
struct Z<2, Y, A, B> { 
    constexpr Z(int W) { } 
}; 

int main() { 
    constexpr Z<0, void> z1; 
    constexpr Z<2, void> z2{42}; 
} 

Если это хороший компромисс во многом зависит от реальной проблемы.