Разрешение параметра шаблона быть только определенными типами и принятие решения на его основе - PullRequest
0 голосов
/ 15 января 2019

Допустим, у меня есть два класса MyClass_one, MyClass_two

И у меня есть функция, которая принимает только их в качестве первого параметра

template<typename T,typename ...Ts>
void doSomething(T one, Ts...two){}

Теперь для простоты, если параметр one равен MyClass_one, он должен вывести «im one», если его MyClass_two, то вывести «im two».

Как на самом деле этого добиться? Единственное решение, которое я придумал, действительно ужасно и не содержит ошибок компиляции:

template<typename T> isOne{ static const bool value = false}
template<> isOne<MyClass_one>{ static const bool value = true}

template<typename T> isTwo{ static const bool value = false}
template<> isTwo<MyClass_two>{ static const bool value = true}

template<typename T, typename ... Ts>
void doSomething(T one, Ts...two){
  if( isOne<T>::value ) { cout << "im one" << endl;}
  else if ( isTwo<T>::value){ cout <<"im two" << endl;}
}

Однако, как реализовать проверку ошибок компилятора без перегрузки (множественное определение функции doSomething()), например, функция не будет компилироваться, если передано что-то еще, кроме MyClass_one или MyClass_two.

спасибо за помощь.

Ответы [ 3 ]

0 голосов
/ 15 января 2019

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

template<typename T> void theThing(T one);

template<>
void theThing<MyClass_one>(MyClass_one one) {
    cout << "im one" << endl;
}

template<>
void theThing<MyClass_two>(MyClass_two one) {
    cout << "im two" << endl;
}

template<typename T, typename ... Ts>
void doSomething(T one, Ts...two) {
    theThing(one);
}

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

0 голосов
/ 15 января 2019

без перегрузки

но перегрузка здесь делает код простым:

template<typename ... Ts>
void doSomething(MyClass_one, Ts...two){
    cout << "im one" << endl;
}

template<typename ... Ts>
void doSomething(MyClass_two, Ts...two){
    cout <<"im two" << endl;
}
0 голосов
/ 15 января 2019

Если вы можете использовать C ++ 17, вы можете использовать if constexpr:

template<typename T, typename ... Ts>
void doSomething(T one, Ts...two){
  if constexpr ( isOne<T>::value ) { cout << "im one" << endl;}
  else if constexpr ( isTwo<T>::value){ cout <<"im two" << endl;}
}

Конечно, isOne<T>::value и isTwo<T>::value должны быть static constexpr переменными.

Если вы хотите проверить типы первого аргумента функции, применяется тот же подход, только нет необходимости что-то вроде isOne и isTwo, вы можете использовать std::is_same_v, чтобы увидеть, является ли первый аргумент MyClassOne или MyClassTwo:

#include <iostream> 
#include <type_traits>
#include <vector> 

class MyClassOne {}; 
class MyClassTwo {}; 

template<typename T, typename ... Ts>
void doSomething(T one, Ts...two){
  if constexpr ( std::is_same_v<T, MyClassOne> ) 
    std::cout << "im one" << std::endl;
  else if constexpr ( std::is_same_v<T, MyClassTwo> )
    std::cout <<"im two" << std::endl;
  else
    static_assert(false, "Only MyClassOne and MyClassTwo are permitted first arguments.");
}
int                                                                                                                                         
main(int argc, char **argv) { 

    MyClassOne one; 
    MyClassTwo two; 

    doSomething(one, 1.5, two); 
    doSomething(two, 'c', one);

    std::vector<MyClassOne> onesVector;
    doSomething(onesVector, 1.0); 

}  

std::is_same_v<A,B> приводит к значению true, если типы A и B совпадают. Это отвечает на ваш вопрос: «если параметром один является MyClass_one, он должен вывести« im one », если его MyClass_two должен вывести« im two ».», И завершается неудачно во время компиляции, если первый аргумент имеет тип, отличный от myClassOne или myClassTwo.

Редактировать : добавлено static_assert, обеспечивающее сбой компиляции, если первым аргументом является что-то еще, кроме MyClassOne или MyClassTwo, как это было предложено Джастином Таймом в комментарии.

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