2015-01-05 5 views
1

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

class c2Type 
{ 
    // some data members... 
}; 

template<typename T, typename isC2Type = typename std::enable_if< 
       std::is_same<c2Type, typename std::decay<T>::type>::value>::type> 
    void configurationMessageHandler(T&& message) 
{ 
    // some stuff... 
    mapAddress(std::forward<c2Type>(message)); 
} 

mapAddress(c2Type&& message) 
{ 
    // do stuff... 
}; 

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

template<typename T> 
using isC2Type = typename std::enable_if< 
      std::is_same<c2Type, typename std::decay<T>::type>::value>::type; 

, который я думал бы сделать configurationMessageHandler шаблон выглядеть

template<typename T, isC2Type<T>> 

но не компилируется. Как я могу правильно использовать псевдонимы в этом случае?

+4

Вы имеете в виду 'template >'? – Jarod42

+0

Это все трюк! Благодаря! –

ответ

2

Я надеюсь, что это может вам помочь.

template<class U, class T, 
     class= std::enable_if_t<std::is_same<std::decay_t<T>, U>::value, T>> 
using LimitTo = T; 

template<class T> 
void configurationMessageHandler(LimitTo<c2Type,T>&& message){ 
    // some stuff... 
    mapAddress(std::forward<T>(message)); 
    //!! Use T because the reference of c2Type maybe has cv-qualify 
} 

Даже при наличии большого числа параметров, например:

void foo(int); 
template<class A, class B, class C> 
void foo(LimitTo<int,A>&& , LimitTo<float,B>&& , LimitTo<bool,C>&&); 
template<class T> 
void foo(LimitTo<string,T>&&); 

Однако, есть некоторые подводные камни с этим трюком:

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

    template<class...Args> 
        void foo(LimitTo<double,Args>&&... args){} 
    
  2. Использовать параметры по умолчанию, чтобы избежать двусмысленностей, например. в отношении таких конструкторов:

    template<class T> 
        Ctor(LimitTo<string,T>&&,string* =nullptr) {} //string* or anything else 
    
        template<class T> 
        Ctor(LimitTo<double,T>&&, double* =nullptr) {} 
    

Наследственных конструкторы будут вызывать некоторые проблемы в качестве параметров по умолчанию не могут быть унаследованы. Поэтому измените его на:

template<class T> 
Ctor(LimitTo<string,T>&&,string*) {} 
template<class T> 
Ctor(LimitTo<double,T>&&, double*) {} 
+0

Это очень умная идея. Я думаю, что вызов 'Tself', что-то вроде' LimitTo' или 'UniversalRef' с изменением порядка параметров шаблона, сделает его более читаемым. –

+0

@NicolasHolthaus да, LimitTo или UniversalRef также является хорошим именем. Я думал, что сам является средством самого Т. – Landersing

+0

@NicolasHolthaus Я обнаружил, что существует потенциальная ошибка, и мы должны использовать forward T вместо пересылки реального типа – Landersing