строковый литерал - массив, указатель, шаблон функции
От: _Winnie Россия C++.freerun
Дата: 14.03.06 18:35
Оценка:
void WideToUTF8(wchar_t const *input, size_t size, std::string &out); //спрятана в .cpp файле.

inline void WideToUTF8(const std::wstring &str, std::string &out) 
{
    WideToUTF8(str.data(), str.size(), out);
}

template <int N>
inline void WideToUTF8(wchar_t const (&string_literal)[N], std::string &out)
{
    WideToUTF8(string_literal, N-1, out);
}

inline void WideToUTF8(wchar_t const *input, std::string &out) 
{
    WideToUTF8(input, wcslen(input), out);
}


Когда я вызываю
WideToUTF8(L"hello", s)
то вызывается версия которая принимает указатель, а не ссылку на массив. Почему? Как исправить?
Правильно работающая программа — просто частный случай Undefined Behavior
Re: строковый литерал - массив, указатель, шаблон функции
От: korzhik Россия  
Дата: 14.03.06 18:39
Оценка: :)
Здравствуйте, _Winnie, Вы писали:

_W>Когда я вызываю

_W>WideToUTF8(L"hello", s)
_W>то вызывается версия которая принимает указатель, а не ссылку на массив. Почему?

Наверно потому что нешаблонная функция имеет преимущество перед шаблонной.

оффтоп (злостный)
сейчас возник экспромт связанный с твоим ником: in Winnie veritas
Re: строковый литерал - массив, указатель, шаблон функции
От: _nn_  
Дата: 14.03.06 18:52
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>
_W>void WideToUTF8(wchar_t const *input, size_t size, std::string &out); //спрятана в .cpp файле.

_W>inline void WideToUTF8(const std::wstring &str, std::string &out) 
_W>{
_W>    WideToUTF8(str.data(), str.size(), out);
_W>}

_W>template <int N>
_W>inline void WideToUTF8(wchar_t const (&string_literal)[N], std::string &out)
_W>{
_W>    WideToUTF8(string_literal, N-1, out);
_W>}

_W>inline void WideToUTF8(wchar_t const *input, std::string &out) 
_W>{
_W>    WideToUTF8(input, wcslen(input), out);
_W>}
_W>


_W>Когда я вызываю

_W>WideToUTF8(L"hello", s)
_W>то вызывается версия которая принимает указатель, а не ссылку на массив. Почему? Как исправить?

Баг VC.
В VC 8.0 тоже он есть
Об этом писали на форуме.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: строковый литерал - массив, указатель, шаблон функции
От: shank  
Дата: 14.03.06 19:05
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Баг VC.

__>В VC 8.0 тоже он есть
__>Об этом писали на форуме.

Почему баг?
У обоих функций точное соответствие, при этом предпочтение отдается нешаблонной, как сказал korzhik.
См. 13.3.3.1.1/3 табл. 9, Array-to-pointer conversion имеет rank — Exact Match.
Вроде так...

Как исправить? Сделать обе шаблонными?
Re[2]: строковый литерал - массив, указатель, шаблон функции
От: Нахлобуч Великобритания https://hglabhq.com
Дата: 14.03.06 19:17
Оценка:
Здравствуйте, korzhik, Вы писали:

K>оффтоп (злостный)

K>сейчас возник экспромт связанный с твоим ником: in Winnie veritas

Это "Истиина в словах Винни" штоль ?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
HgLab: Mercurial Server and Repository Management for Windows
Re[3]: строковый литерал - массив, указатель, шаблон функции
От: korzhik Россия  
Дата: 14.03.06 19:20
Оценка:
Здравствуйте, Нахлобуч, Вы писали:

Н>Здравствуйте, korzhik, Вы писали:


K>>оффтоп (злостный)

K>>сейчас возник экспромт связанный с твоим ником: in Winnie veritas

Н>Это "Истиина в словах Винни" штоль ?


ну типа того
Re[3]: строковый литерал - массив, указатель, шаблон функции
От: _nn_  
Дата: 14.03.06 19:29
Оценка:
Здравствуйте, shank, Вы писали:

S>Здравствуйте, _nn_, Вы писали:


__>>Баг VC.

__>>В VC 8.0 тоже он есть
__>>Об этом писали на форуме.

S>Почему баг?

S>У обоих функций точное соответствие, при этом предпочтение отдается нешаблонной, как сказал korzhik.
S>См. 13.3.3.1.1/3 табл. 9, Array-to-pointer conversion имеет rank — Exact Match.
S>Вроде так...
Для функции, которая получает ссылку, нет вообще никакого преобразования и она проигрывает ?

S>Как исправить? Сделать обе шаблонными?


В VC следущий код не работает правильно:
void f(const char (&a)[2]){}
void f(const char* a){}

f("a"); // error C2668: 'f' : ambiguous call to overloaded function  :maniac:

VC не может выбрать правильную функцию (№1).

Если первая функция шаблонная:
template<size_t N>
void f(const char (&a)[N]){}

void f(const char* a){}

Вызывается вторая функция.

Если вторая шаблонная:
void f(const char (&a)[2]){}

template<typename T>
void f(const T* a){}

Вызывается первая функция, как и должно быть.

Переписать функции как шаблон не получится, т.к. тогда тоже у VC возникает неоднозначность.
template<size_t N>
void f(const char (&a)[N]){}

template<typename T>
void f(const T* a){}

f("a"); // error C2668: 'f' : ambiguous call to overloaded function
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: строковый литерал - массив, указатель, шаблон функции
От: korzhik Россия  
Дата: 14.03.06 19:38
Оценка: 6 (1)
Здравствуйте, _Winnie, Вы писали:

_W>Когда я вызываю

_W>WideToUTF8(L"hello", s)
_W>то вызывается версия которая принимает указатель, а не ссылку на массив. Как исправить?

возможно тебе тут надо решение подобное boost.range

#include "boost/range.hpp"

void WideToUTF8(wchar_t const *input, size_t size, std::string &out);

template<class Range>
inline 
void WideToUTF8( const Range& c, std::string &out)
{
    return WideToUTF8(boost::begin(c), boost::size(c), out);
}

int main()
{
    std::string s;
    WideToUTF8(L"hello", s);
}
Re[4]: строковый литерал - массив, указатель, шаблон функции
От: shank  
Дата: 14.03.06 19:41
Оценка: 1 (1) +1
Здравствуйте, _nn_, Вы писали:


__>В VC следущий код не работает правильно:

__>
__>void f(const char (&a)[2]){}
__>void f(const char* a){}

__>f("a"); // error C2668: 'f' : ambiguous call to overloaded function  :maniac: 
__>

__>VC не может выбрать правильную функцию (№1).

Comeau согласен с VC. (Вроде как exact match )

__>Если первая функция шаблонная:

__>
__>template<size_t N>
__>void f(const char (&a)[N]){}

__>void f(const char* a){}
__>

__>Вызывается вторая функция.

__>Если вторая шаблонная:

__>
__>void f(const char (&a)[2]){}

__>template<typename T>
__>void f(const T* a){}
__>

__>Вызывается первая функция, как и должно быть.

А кто спорит?

__>Переписать функции как шаблон не получится, т.к. тогда тоже у VC возникает неоднозначность.

__>
__>template<size_t N>
__>void f(const char (&a)[N]){}

__>template<typename T>
__>void f(const T* a){}

__>f("a"); // error C2668: 'f' : ambiguous call to overloaded function
__>


Я предлагал так:
template <int N>
inline void func(wchar_t const (&string_literal)[N])
{
    std::cout << "literal\n";
}

template <int>
inline void func(wchar_t const *input)
{
    std::cout << "ptr\n";
}

int main()
{
    func(L"hello");
}
Re[5]: строковый литерал - массив, указатель, шаблон функции
От: _nn_  
Дата: 14.03.06 19:54
Оценка:
Здравствуйте, shank, Вы писали:

S>Здравствуйте, _nn_, Вы писали:


S>Я предлагал так:

S>
S>template <int N>
S>inline void func(wchar_t const (&string_literal)[N])
S>{
S>    std::cout << "literal\n";
S>}

S>template <int>
S>inline void func(wchar_t const *input)
S>{
S>    std::cout << "ptr\n";
S>}

S>int main()
S>{
S>    func(L"hello");
S>}
S>


Я неправильно понял вашу идею сначала
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: строковый литерал - массив, указатель, шаблон функции
От: korzhik Россия  
Дата: 14.03.06 20:04
Оценка: +1
Здравствуйте, korzhik, Вы писали:

K>Здравствуйте, _Winnie, Вы писали:


_W>>Когда я вызываю

_W>>WideToUTF8(L"hello", s)
_W>>то вызывается версия которая принимает указатель, а не ссылку на массив. Как исправить?

K>возможно тебе тут надо решение подобное boost.range


кстати оказалось что boost::range для литералов вызывает strlen. печально
Re[6]: строковый литерал - массив, указатель, шаблон функции
От: shank  
Дата: 14.03.06 20:08
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Я неправильно понял вашу идею сначала

А теперь я ее не понял
Почему компилится как я показал раньше, но не компилится так?

inline void func(wchar_t const (&string_literal)[6])
{
    std::cout << "literal\n";
}


inline void func(wchar_t const *input)
{
    std::cout << "ptr\n";
}

int main()
{
    func(L"hello");//неоднозначность
}

Ведь логика та же...
Re[3]: строковый литерал - массив, указатель, шаблон функции
От: _nn_  
Дата: 14.03.06 20:09
Оценка:
Здравствуйте, korzhik, Вы писали:

K>Здравствуйте, korzhik, Вы писали:


K>>Здравствуйте, _Winnie, Вы писали:


_W>>>Когда я вызываю

_W>>>WideToUTF8(L"hello", s)
_W>>>то вызывается версия которая принимает указатель, а не ссылку на массив. Как исправить?

K>>возможно тебе тут надо решение подобное boost.range


K>кстати оказалось что boost::range для литералов вызывает strlen. печально


А что если предложить улучшение boost.range ?
Или нет переносимого решения раз не реализовали ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: строковый литерал - массив, указатель, шаблон функции
От: rg45 СССР  
Дата: 14.03.06 20:09
Оценка: 12 (3)
"_Winnie" <23256@users.rsdn.ru> wrote in message news:1782668@news.rsdn.ru...
>...
> Когда я вызываю
> WideToUTF8(L"hello", s)
> то вызывается версия которая принимает указатель, а не ссылку на массив. Почему? Как исправить?

Предлагаю такой вариант решения:

void WideToUTF8(wchar_t const *input, size_t size, std::string &out);

template<typename> struct WideToUTF8Helper;

template<> 
struct WideToUTF8Helper<const wchar_t*>
{
  static void process(wchar_t const *input, std::string &out) 
  {
    WideToUTF8(input, wcslen(input), out);
  }
};

template<int N> 
struct WideToUTF8Helper<const wchar_t[N]>
{
  static void process(const wchar_t (&string_literal)[N], std::string &out)
  {
    WideToUTF8(string_literal, N-1, out);
  }
};

template<typename T>
void WideToUTF8(const T& input, std::string &out) 
{
  WideToUTF8Helper<T>::process(input, out);
}

int main()
{
  std::string out;
  
  WideToUTF8(L"Hello", out);
  WideToUTF8((const wchar_t*)L"Hello", out);

}


Убирая поочередно 'static' перед функциями 'process' можно убедиться, что вызывается то, что нужно
Posted via RSDN NNTP Server 1.9
--
Справедливость выше закона. А человечность выше справедливости.
Re[7]: строковый литерал - массив, указатель, шаблон функции
От: _nn_  
Дата: 14.03.06 20:18
Оценка:
Здравствуйте, shank, Вы писали:

S>Здравствуйте, _nn_, Вы писали:


__>>Я неправильно понял вашу идею сначала

S>А теперь я ее не понял
S>Почему компилится как я показал раньше, но не компилится так?

S>
S>inline void func(wchar_t const (&string_literal)[6])
S>{
S>    std::cout << "literal\n";
S>}


S>inline void func(wchar_t const *input)
S>{
S>    std::cout << "ptr\n";
S>}

S>int main()
S>{
S>    func(L"hello");//неоднозначность
S>}
S>

S>Ведь логика та же...

Я в посте
Автор: _nn_
Дата: 14.03.06
как раз писал об этом.
Вы ответили, что комо также не съел этот код .
Значит по стандарту неоднозначность ?

Приведение типа к ссылке на массив не помогает
f(static_cast<const wchar_t (&)[6]>("hello")); // Ambiguity


Однако приведение типа к указателю устраняет неоднозначность, что и ожидается.
f(static_cast<const wchar_t*>("hello")); // OK
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[5]: строковый литерал - массив, указатель, шаблон функции
От: _nn_  
Дата: 14.03.06 20:20
Оценка:
Здравствуйте, shank, Вы писали:

S>Я предлагал так:

S>
S>template <int N>
S>inline void func(wchar_t const (&string_literal)[N])
S>{
S>    std::cout << "literal\n";
S>}

S>template <int>
S>inline void func(wchar_t const *input)
S>{
S>    std::cout << "ptr\n";
S>}

S>int main()
S>{
S>    func(L"hello");
S>}
S>


А что будет если написать ?:
func<6>(L"hello");

Правильно, неоднозначность
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: строковый литерал - массив, указатель, шаблон функции
От: Demay  
Дата: 15.03.06 06:30
Оценка:
Здравствуйте, _Winnie, Вы писали:

Можно явно указать шаблонную функцию:
WideToUTF8<>(L"hello", s);
Re[2]: строковый литерал - массив, указатель, шаблон функции
От: bolshik Россия http://denis-zhdanov.blogspot.com/
Дата: 15.03.06 07:41
Оценка:
Здравствуйте, rg45, Вы писали:

а что означает использование символа 'L' в следующей строке?
  WideToUTF8(L"Hello", out);
http://denis-zhdanov.blogspot.com
Re[3]: строковый литерал - массив, указатель, шаблон функции
От: rg45 СССР  
Дата: 15.03.06 07:46
Оценка:
"bolshik" <29601@users.rsdn.ru> wrote in message news:1783194@news.rsdn.ru...
> Здравствуйте, rg45, Вы писали:
>
> а что означает использование символа 'L' в следующей строке?
>
>   WideToUTF8(L"Hello", out);
>

Это означает, что каждый символ этого строкового литерала имеет размер два байта (unicode)
Posted via RSDN NNTP Server 1.9
--
Справедливость выше закона. А человечность выше справедливости.
Re[4]: строковый литерал - массив, указатель, шаблон функции
От: bolshik Россия http://denis-zhdanov.blogspot.com/
Дата: 15.03.06 07:53
Оценка:
Здравствуйте, rg45, Вы писали:

R>Это означает, что каждый символ этого строкового литерала имеет размер два байта (unicode)


правильно я понимаю, что это относится только к строковым литералам?
Не поделишься ссылкой, где можно почитать, что еще можно применять к строковым литералам?
http://denis-zhdanov.blogspot.com
Re[5]: строковый литерал - массив, указатель, шаблон функции
От: rg45 СССР  
Дата: 15.03.06 08:19
Оценка: 3 (1)
"bolshik" <29601@users.rsdn.ru> wrote in message news:1783221@news.rsdn.ru...
> Здравствуйте, rg45, Вы писали:
>
> R>Это означает, что каждый символ этого строкового литерала имеет размер два байта (unicode)
>
> правильно я понимаю, что это относится только к строковым литералам?
> Не поделишься ссылкой, где можно почитать, что еще можно применять к строковым литералам?

Вообще символ L образовался от Long и может применяться не только к строковым литералам.
Например литерал 123123123123123123L задает 64-разрядную целочисленную знаковую константу.
п. 2.13 стандарта дает подробное описание всех возможных в С++ литералов.
В MSDN это тоже есть.
Posted via RSDN NNTP Server 1.9
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: строковый литерал - массив, указатель, шаблон функции
От: remark Россия http://www.1024cores.net/
Дата: 15.03.06 08:26
Оценка: +1
Здравствуйте, Demay, Вы писали:

D>Здравствуйте, _Winnie, Вы писали:


D>Можно явно указать шаблонную функцию:

D>
D>WideToUTF8<>(L"hello", s);
D>



В этом-то и фича, что бы явно ничего не указывать. Шаблонная функция здесь выступает в роли хелпера, о которой вообще никто не должен знать по-хорошему. Просто тихо оптимизирует вычисление длины. Ну я так понимаю ситуацию.
Второй момент, что возлагать это на юзера плохо — всё равно ведь не досмотрит — компилятор надёжнее.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[6]: строковый литерал - массив, указатель, шаблон функции
От: bolshik Россия http://denis-zhdanov.blogspot.com/
Дата: 15.03.06 08:30
Оценка:
Здравствуйте, rg45, Вы писали:

R>Вообще символ L образовался от Long и может применяться не только к строковым литералам.

R>Например литерал 123123123123123123L задает 64-разрядную целочисленную знаковую константу.
R>п. 2.13 стандарта дает подробное описание всех возможных в С++ литералов.
R>В MSDN это тоже есть.

спасибо
http://denis-zhdanov.blogspot.com
Re: строковый литерал - массив, указатель, шаблон функции
От: remark Россия http://www.1024cores.net/
Дата: 15.03.06 08:39
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>...


_W>Когда я вызываю

_W>WideToUTF8(L"hello", s)
_W>то вызывается версия которая принимает указатель, а не ссылку на массив. Почему? Как исправить?


Смотри — с такими вещами надо быть осторожно. Если эта функция используется только как ты привёл: WideToUTF8(L"hello", s); то тогда нормально. А если она используется по-разному и разными людьми, то можно получить нехорошую ситуацию:

wchar_t buf[4096] = {0};
...
someFuncThatFillsBuffer(buf, 1024, ...);

std::string s;
WideToUTF8(buf, s);


В выделенной строчке получишь поведение, которое не совсем ожидалось.


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

А вот для выходных буферов это действительно очень полезно:

std::string s = "...";
wchar_t buf[4096] = {0};
WideToUTF8(s, buf);


Размер массива в WideToUTF8 можно сразу на 1 уменьшить, что бы не потереть завершающий ноль.
Тут сразу 3 оптимизации: и память динамически не выделяется под выходной буфер и длина выходного буфера не считается и длина входного буфера не считается, т.к. std::string



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.