Мотивация:Возможно ли перегрузить функцию, которая может указывать фиксированный массив из указателя?
Почти для удовольствия, я пытаюсь написать функцию перегрузки, которая может отличить друг от друга, является ли аргумент массив фиксированного размера или указатель.
double const d[] = {1.,2.,3.};
double a;
double const* p = &a;
f(d); // call array version
f(p); // call pointer version
Я нахожу это особенно трудно из-за хорошо известный факт, что массивы распадаются на указатель раньше, чем позже. Наивный подход состоит в том, чтобы написать
void f(char const* c){...}
template<size_t N> void f(char const(&a)[N]){...}
К сожалению, это не сработает. Поскольку в лучшем случае компилятор определяет вызов массива f(d)
выше, чтобы быть неоднозначным.
Частичное решение:
Я пробовал много вещей, и ближе всего я мог бы получить был следующий конкретный код. Заметим также, что в этом примере кода я использую char
вместо double
, но он очень похож в конце.
Во-первых, я должен использовать SFINAE для отключения преобразований (от массива ref до ptr) в версии указателя функции. Во-вторых, мне пришлось перегружать все возможные размеры массивов (вручную).
[компилируемый код]
#include<type_traits> // for enable_if (use boost enable_if in C++98)
#include<iostream>
template<class Char, typename = typename std::enable_if<std::is_same<Char, char>::value>::type>
void f(Char const* dptr){std::cout << "ptr" << std::endl;} // preferred it seems
void f(char const (&darr)[0]){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[1]){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[2]){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[3]){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[4]){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[5]){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[6]){std::cout << "const arr" << std::endl;} // this is the one called in this particular example
// ad infinitum ...
int main(){
f("hello"); // print ptr, ok because this is the fixed size array
f(std::string("hello").c_str()); // print arr, ok because `c_str()` is a pointer
}
Это работает, но проблема в том, что я должен повторить функцию для всех возможных значений N
и использование template<size_t N>
заставляет меня вернуться к площади ноль, потому что с помощью параметра шаблона два вызова возвращаются на равные. В других работах template<size_t N> void f(char const(&a)[N]){std::cout << "const arr" << std::endl;}
не помогает.
Есть ли способ обобщить вторую перегрузку, не возвращаясь к двусмысленному вызову? или есть какой-то другой подход?
Ответ на C++ или C++ 1XYZ также приветствуется.
Две детали: 1) Я использовал clang
для экспериментов выше, 2) фактическое f
будет в конечном итоге к operator<<
, я думаю, что знаю, если это будет иметь значение для решения.
Резюме решений (основано на других людей ниже) и адаптированы к конкретному типу char
примера. И, кажется, зависит от делая char const*
указатель менее очевидно для компилятора:
1) Один странно (переносной), (из комментария @dyp?.) Добавление ссылки спецификатор версии указателя:
template<class Char, typename = typename std::enable_if<std::is_same<Char, char>::value>::type>
void f(Char const* const& dptr){std::cout << "ptr" << std::endl;}
template<size_t N>
void f(char const (&darr)[N]){std::cout << "const arr" << std::endl;}
2) Один элегантный (частный случай с @ user657267)
template<class CharConstPtr, typename = typename std::enable_if<std::is_same<CharConstPtr, char const*>::value>::type>
void f(CharConstPtr dptr){std::cout << "ptr" << std::endl;}
template<size_t N>
void f(char const (&darr)[N]){std::cout << "const arr" << std::endl;}
Как об использовании 'зОго :: array' вместо исходных массивов? – user657267
@ user657267, спасибо, я просто хочу решение, не связанное с изменением кода в основной функции. Причина, по которой вы хотите знать, - это то, что я хочу передать жесткий текст («привет») из текста, полученного в результате указателя. – alfC
Есть странная работа: http://coliru.stacked-crooked.com/a/37214a2859f7e78d Более очевидным решением является использование отправки тегов. – dyp