Как заставить трейты принимать пакет параметров? - PullRequest
2 голосов
/ 17 июня 2020

Я определяю некоторые черты типа следующим образом:

template <typename T>
struct has_something
{
    static constexpr bool value = false;
};

template <> 
struct has_something<int>
{
    static constexpr bool value = true;
};

template <typename T>
constexpr bool has_something_v = has_something<T>::value;

И шаблон функции has_something_v является требованием для параметра функции:

template <typename T, typename = std::enable_if_t<has_something_v<T>>>
void some_function(const T temp)
{
}

Когда я вызываю его с помощью неправильный тип:

struct wrong_type
{
};

void f ()
{
    some_function(wrong_type());
}

компилятор дал мне правильное сообщение об ошибке:

/tmp/untitled/main.cpp:23: candidate template ignored: requirement 'has_something_v<wrong_type>' was not satisfied [with T = wrong_type]

но когда я вызвал с помощью другой функции шаблона:

template <typename ...T, typename = std::enable_if_t<has_something_v<T...>>>
void some_function(const T... args)
{
    (some_function(args), ...);
}

void f ()
{
    some_function(1, 2, a());
}

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

Сообщение об ошибке компилятора

И если я удалю std::enable_if из последней функции шаблона, все будет работать нормально, пока я не отправлю тип wrong_type функции, что приведет к сбою программы.

Для пакета параметров я написал следующее:

template <typename ...T>
struct has_something
{
    static bool value;

    static constexpr bool c(T... args)
    {
        value = (args && ...);
        return value;
    }
};

template <>
struct has_something<int>
{
    static constexpr bool value = true;
};

template <typename ...T>
const bool has_something_v = has_something<T...>::value;

Но он все равно не работает.

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

1 Ответ

1 голос
/ 17 июня 2020

Если вы хотите, чтобы трейт принимал пакет параметров и его значение было true, только если пакет параметров имеет единственный тип и этот тип int, вам нужно лишь немного изменить свой код:

#include <iostream>
#include <type_traits>

template <typename...T>
struct has_something : std::false_type {};

template <> 
struct has_something<int> : std::true_type {};

template <typename... T>
constexpr bool has_something_v = has_something<T...>::value;

int main() {
    std::cout << has_something_v<int>;
    std::cout << has_something_v<double>;    
    std::cout << has_something_v<int,double>;
}

Использование std::true_type и std::false_type делает записи немного короче. Мне нужно было только заставить трейт принимать пакет параметров, специализация может остаться прежней.

И последнее, но не менее важное: вам следует выбрать имя получше. Например, is_one_int будет намного лучше, чем something.

PS: SFINAE можно использовать для создания ошибок компилятора, но часто простой static_assert - лучший выбор для получения чистого сообщения:

template <typename...T>
void foo(T...args) {
    static_assert( is_one_int_v<T...>, " put nice message here");
}

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

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