2017-01-17 5 views
0

Я хотел бы использовать безупречную переадресацию на шаблонизированную функцию, чтобы гарантировать, что l -значность или r -значность сохранены, но в то же время я бы хотел наложить определенные ограничения на возможные типы параметров.Идеальная пересылка с ограничениями типа

Предположим, например, я просто хочу ограничить T вызываемому объекту. Следующий подход выглядит правильно мне

template<typename T> 
typename std::enable_if<std::is_callable<T>>::value>::type myFun(T&& val) 
{ 
    foo(std::forward<T>(val)); 
} 

, но так как я до сих пор еще не вполне комфортно с различными SFINAE нюансы я был бы признателен за чужое мнение.

Будет ли это правильным и идиоматическим способом?

+0

Почему не специализировать шаблон для 'Allowed_Type' и отключить общий шаблон? – wally

+0

Будет ли это лучшим решением? –

+2

(Почти) всегда предпочитают перегрузку, когда вы хотите обрабатывать определенный тип. – AndyG

ответ

3

std::is_callable - особенность C++ 17, между прочим.

Во всяком случае, поскольку ваша функция myFun ничего не возвращает, немного странно положить enable_if в качестве возвращаемого значения. Да, это станет void при выборе шаблона, но это, вероятно, более разборчивым, чтобы поместить его в качестве шаблона по умолчанию аргумента:

template<typename T, std::enable_if_t<std::is_callable_v<T()>, int> = 0> 
void myFun(T&& val) 
{ 
    foo(std::forward<T>(val)); 
} 

Demo

Хотя было бы немного странно для enable_if существовать в вакууме. По крайней мере, мы должны охватить все типы, которые не вписываются в и предоставить пользователю с хорошей ошибки компилятора с помощью static_assert:

template<typename T, std::enable_if_t<std::is_callable_v<T()>, int> =0> 
void myFun(T&& val) 
{ 
    foo(std::forward<T>(val)); 
} 

template<typename T, std::enable_if_t<!std::is_callable_v<T()>, int> =0> 
void myFun(T&& val) 
{ 
    static_assert(sizeof(T) == 0, "myFun is only callable with an argument that can be called as a function with no params"); 
} 

Demo2

+0

За исключением проблемы, из-за которой MSVC сломан и не понимает его, 'std :: enable_if_t {}, int> = 0' имеет лучшие свойства разрешения перегрузки, чем 'typename = std :: enable_if_t {}>' does. – Yakk

+0

@Yakk: Обновлено, спасибо. Есть ли предпочтение между 'std :: enable_if_t {}, int> = 0' и' template :: значение, int> = 0> 'кроме того, что в первом будет неявное преобразование в bool и нет необходимости проверять' :: value'? – AndyG

+0

':: value' - это еще 5 символов, чем' {} '. Альтернативно, 'std :: is_callable_v ', учитывая, что это свойство C++ 17 также является коротким. – Yakk

Смежные вопросы