Сокращение для перегрузки нескольких функций - PullRequest
0 голосов
/ 21 ноября 2018

Предполагая, что у меня есть код, подобный приведенному ниже:

bool isString(char* arg) { return true; }
bool isString(const char* arg) { return true; }
bool isString(std::string arg) { return true; }

// Any other type...
template <typename type> bool isString(type arg) { return false; }

Вопрос в том, допускает ли C ++ любой вероятный способ сократить синтаксис ниже до чего-то похожего на концепцию ниже (синтаксическая стенография / sugar):

// Could be `char*`, `const char*` or `std::string` here.
bool isString([char*, const char*, std::string] arg) { return true; }

// Any other type...
template <typename type> bool isString(type arg) { return false; }

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

Представьте, что еслиЯ должен был проверить на 100+ типов данных, если они действительны или нет, я бы хотел быстро использовать более короткий способ кодирования, чем набирать все 100 перегруженных функций

Конечно, недостатокэта синтаксическая стенография заключается в том, что тип данных arg не может быть дифференцирован (в отличие от стандартной перегрузки функций).

Ответы [ 4 ]

0 голосов
/ 21 ноября 2018

Функция здесь не нужна, потому что значение аргумента всегда игнорируется.Достаточно (const) шаблона переменной.

#include <string>
#include <iostream>
template <class> const bool is_string = false;
template<> const bool is_string<const char*> = true;
template<> const bool is_string<std::string> = true;

int main() {
   const char* z;
   std::string p;
   int q;

   std::cout << is_string<decltype(z)> << "\n"; 
   std::cout << is_string<decltype(p)> << "\n";
   std::cout << is_string<decltype(q)> << "\n";
}

Если требуется интерфейс функции, тривиально предоставить

 template<class T>
 constexpr bool is_string_f(const T&) {
     return is_string<T>;
 }

Хорошо, вы говорите, что все эти специализации все еще слишком длинны, чтобынапиши, можем мы их еще сократить?Да, мы можем.

#include <type_traits>
template<class X, class ... args>
const bool type_is_one_of = (false || ... || std::is_same<X, args>::value);
template <class T> 
bool is_string = type_is_one_of<T, char*, const char*, std::string>;

Живой пример на ideone .

0 голосов
/ 21 ноября 2018

Может

#include <type_traits>
#include <string>

template<typename T>
bool is_string(T)
{
    return std::is_constructible<std::string, T>::value;
}

хватит?

0 голосов
/ 21 ноября 2018

Вы можете напрямую сделать:

template <typename T>
constexpr bool isString()
{
    return std::is_same<T, const char*>::value
        || std::is_same<T, char*>::value
        || std::is_same<T, std::string>::value;
}

, тогда, если вам нужно установить перегрузки, вы можете использовать SFINAE:

template <typename T>
std::enable_if_t<isString<T>()> foo(/**/) { /*..*/}

template <typename T>
std::enable_if_t<!isString<T>()> foo(/**/) { /*..*/}

или if constexpr (c ++ 17):

template <typename T>
void foo(/**/)
{
    if constexpr (isString<T>()) {
        /*..*/
    } else {
        /*..*/
    }
}
0 голосов
/ 21 ноября 2018

Вероятно, лучшим подходом было бы начать с определения черты, идентифицирующей ваши типы:

template<typename> struct is_string : std::false_type{};

template<> struct is_string<char*>       : std::true_type{};
template<> struct is_string<char const*> : std::true_type{};
template<> struct is_string<std::string> : std::true_type{};

Тогда вы можете делать все виды вещей.Например, реализация функции в вашем посте становится такой:

template<typename T> constexpr bool isString(T) { return is_string<T>::value; }

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

template<typename S>
auto needAString(S s) -> std::enable_if_t<is_string<S>::value>;

Некоторые предопределенные черты и утилиты уже доступны в заголовке <type_traits>.

...