Простой вопрос по С++
По-хорошему, этот код не должен компилироваться, т.к. не существует неявного преобразования от const char* до char* (для выбора второго варианта) и невозможно забиндить ссылку на rvalue (для выбора первого варианта когда длина строк различна. В студии косяк
По-хорошему, этот код не должен компилироваться,Comeau тоже сожрал без ошибок
http://www.comeaucomputing.com/tryitout/
g++ (GCC) 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)
Вообще действительно очень загадочная хрень! По всей видимости строковые константы всё-таки можно приводить к char* из соображений совместимости с С. И почему-то к char& (тоже неконстантным). Но почему char& ему нравится больше char* в случае одинаковой длины... А! Наверное, он подставляет в темплейт char* вместо T, то есть получается как бы char*&, а точнее - char[N]&. Хм. Ну а зачем он вообще длину учитывает, она где-нибудь умеет проявляться?
Ну а зачем он вообще длину учитывает, она где-нибудь умеет проявляться?(const)? char [N] для разных N — это разные типы, если я не ошибаюсь.
соответственно, в первом случае сработает шаблон (T = const char [N] а во втором придется применить "нехорошее" преобразование.
(мой компилятор выдает ворнинг).
bugaga ~ $ cat aaa.cpp
#include <stdio.h>
#include <typeinfo>
typedef const char type1 [20];
typedef const char type2 [30];
typedef const char type3 [30];
int main(int argc, char* argv[])
{
printf("type1 %s type2\n", typeid(type1) == typeid(type2) ? "==" : "!=");
printf("type2 %s type3\n", typeid(type2) == typeid(type3) ? "==" : "!=");
return 0;
}
bugaga ~ $ ./a.out
type1 != type2
type2 == type3
мои компиляторы:
bugaga ~ $ icpc --version
icpc (ICC) 10.1 20080801
Copyright (C) 1985-2008 Intel Corporation. All rights reserved.
bugaga ~ $ g++ --version
g++ (GCC) 4.2.4 (Gentoo 4.2.4 p1.0)
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
bugaga ~ $ /opt/sun/sunstudio12/bin/sunCC -V
sunCC: Sun C++ 5.9 Linux_i386 Build47_dlight 2007/05/22
какой же ебанутый все-таки язык. =)
записал пример в блокнотик.
какой же ебанутый все-таки язык. =)Не согласен. Без этого было бы не возможно упрощение синтаксиса для функций c `_s`, т.е. шаблоны вида:
template<N>inline errno_t strcpy_s(char dst[N], char *src){return strcpy_s(dst, N, src);}
и я предполагаю, что ты, не увидев любимого компилятора среди указанных мною,
решил специально своей глупостью меня позлить. =)
ну. по крайней мере тебе ничего не грозит в ответ.
злить меня куда более безопасно, чем пользоваться функциями с `_s`.
злить меня куда более безопасно, чем пользоваться функциями с `_s`.что опасного в этих функциях, не объяснишь? Помимо того, что для компилирования под гцц приходится добавлять к проекту несколько файлов?
Но кое с чем соглашусь. Непонятно, зачем отличать строки с разной длиной на уровне RTTY. В смысле, не понятно, где это может пригодиться.
настолько ужасно развеселило, что я добавил два дурацких предложения к своему комментарию.
я прочитал на msdn, что они очень безопасные и меня это ужасно развеселилоНу, их смысл в том, что это принудительная проверка на потенциальные ошибки переполнения буфера. Во всяком случае, специфичные для сишных библиотечных функций. Необходимости думать они не отменяют, но некоторые случайные ошибки помогают ловить (в debug-е они зануляют буфер перед использованием его и если случайно указать слишком большую длину, это как-то проявится).
Ну а зачем он вообще длину учитывает, она где-нибудь умеет проявляться?sizeof("September") == 10
Вообще действительно очень загадочная хрень! По всей видимости строковые константы всё-таки можно приводить к char* из соображений совместимости с С.Стандарт 4.2.2:
A string literal (2.13.4) that is not a wide string literal can be converted to an rvalue of type “pointer to char”; a wide string literal can be converted to an rvalue of type “pointer to wchar_t”. In either case, the result is a pointer to the first element of the array. This conversion is considered only when there is an explicit appropriate pointer target type, and not when there is a general need to convert from an lvalue to an rvalue. [Note: this conversion is deprecated. See Annex D. ] For the purpose of ranking in overload resolution (13.3.3.1.1 this conversion is considered an arraytopointerОказывается, что все-таки можно приводить строковые литералы к char*, поэтому программа правильно делает, что компилируется. Осталось разобраться, почему шаблон во втором случае является более предпочтительным
conversion followed by a qualification conversion (4.4). [Example: "abc" is converted to “pointer to const char” as an arraytopointer conversion, and then to “pointer to char” as a qualification conversion. ]
почему шаблон во втором случае является более предпочтительнымПотому что не требует приведения типов.
Потому что не требует приведения типов.Нет, приведение здесь выполняется, но по тому же пункту, что я запостил раньше, приведение к const char* больее приоритетное, чем к char*, поэтому и выбирается шаблон из-за точного соответствия.
Стандарт 14.8.3.6
template<class T> void f(T); // declaration
void g
{
f("Annemarie"); // call of f<const char*>
}
Нет, приведение здесь выполняется, но по тому же пункту, что я запостил раньше, приведение к const char* больее приоритетное, чем к char*, поэтому и выбирается шаблон из-за точного соответствия.Не понял тебя. В шаблоне приведения типов нет, тип T как был char const[N], таким и остаётся.
Не понял тебя. В шаблоне приведения типов нет, тип как был char const[N], таким и остаётся.Да, я наврал. Т.к. там ссылка, то приведения никакого нет. Если же ссылку убрать, то T будет - const char*, а не const char[5]
#include <iostream>
#define KERN_ERR
#define printk(str) cout<<str
using namespace std;
template <class T>
void alpha(T& string1, T& string2)
{
if (static_cast<string>(string1).size == static_cast<string>(string2).size
{
printk(KERN_ERR "Know your compiler!\n");
}
else
{
cout<<"Of course C++ is the best"<<endl;
}
}
void alpha(string string1, string string2)
{
if (string1.size != string2.size
{
printk(KERN_ERR "Know your language!\n");
}
else
{
cout<<"Sure C++ is my best"<<endl;
}
}
int main(int argc, char* argv[])
{
alpha("January", "February");
alpha("March", "April");
alpha("May", "June");
alpha("July", "August");
alpha("September", "October");
alpha("November", "December");
return 0;
}
но ничего, качественно отличающегося от ваших, не смог придумать.
P:\temp>cl a.cpp
Open Watcom C/C++ CL Clone for 386 Version 1.7
Portions Copyright (c) 1995-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
a.cpp
P:\temp>a.exe
alpha2
alpha2
gcc version 4.1.2 (Gentoo 4.1.2 p1.0.2)
alpha2
alpha1
P:\temp>cl -v
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.00.9466 for 80x86
Copyright (C) Microsoft Corporation 1984-2001. All rights reserved.
cl : Command line warning D4002 : ignoring unknown option '-v'
cl : Command line error D2003 : missing source filename
P:\temp>a.exe
alpha2
alpha2
думаю тут очень глубоко в спецификации зарыто что-то около "Implementation-defined behavior"
думаю тут очень глубоко в спецификации зарыто что-то около "Implementation-defined behavior"Может просто некоторые implementation не являются полностью standard compliant?
Продолжение банкета!
Если в оригинальном примере взять не void alpha(T&,T& а void alpha(T,T то теперь всегда резолвится темплейтный вариант... Причём если написать там ещё вывод typeid(T).name то в оригинале получается "char const [5]", а в модифицированном варианте - "char const *". Почему так?
Если в оригинальном примере взять не void alpha(T&,T& а void alpha(T,T то теперь всегда резолвится темплейтный вариант...а если сюда же у второго варианта const прописать?
в изначальном const приводил к вызову второго всегда
Почему так?так потому что как только ты пишешь T, так сразу получается возможным преобразование к const char *, а оно более приоритетное, чем char *
зы
кстати когда длина одиннаковая там тоже тип получается const char *, а не char[N]?
А почему ему меньше нравится приводить к const char* & в случае T&? Типа это менее приоритетно, чем просто const char*?
кстати когда длина одиннаковая там тоже тип получается const char *, а не char[N]?да (и мне это кажется странным).
Пора начинать расстреливать авторов языка. Самое главное для кодеров теперь не дай бог никогда не воспользоваться этой херотой!
const char* &т.е., ссылка на ссылку на строку? У меня такое не компилится, что не удивительно. Для этого нужна дополнительная переменная чтобы хранить эту ссылку.
В порядке эксперимента:
$ type tpl.cpp
#include <iostream>
#include <typeinfo>
using namespace std;
template<class T>void sss0(T x, T y){cout<<typeid(T).name<<endl;}
template<class T>void sss1(T& x, T& y){cout<<typeid(T).name<<endl;}
typedef const char O[3];
void sss2(O &a){cout<<typeid(a).name<<endl;}
void main(void)
{
const char *x = "bbb", *y = "a";
sss0(x,y);
// ssschar*)"bbb", (char*)"a");//compile error
sss0("a", "a");
cout<<endl;
sss1(x,y);
sss1("a", "a");
// sss1("a", "aa");//compile error
// sss2("a");//compile error
sss2("aa");
}
$ cl /EHsc tpl.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
tpl.cpp
Microsoft (R) Incremental Linker Version 9.00.21022.08
Copyright (C) Microsoft Corporation. All rights reserved.
/out:tpl.exe
tpl.obj
$ tpl
char const *
char const *
char const *
char const [2]
char const [3]
Но тогда можете объяснить тем, кто все еще в танке, чему равно T если выбирается шаблон от (T&, T&) в случае равных длин строк? const char*? Но почему тогда туда подставляется константа "abc", когда возможна только переменная?
Но тогда можете объяснить тем, кто все еще в танке, чему равно T если выбирается шаблон от (T&, T&) в случае равных длин строк? const char*? Но почему тогда туда подставляется константа "abc", когда возможна только переменная?Нет, T равно const char[N]
Код!Воистину пути преобразований неисповедимы.
Оставить комментарий
bleyman
Код!Что выведет и почему?
Для тех, кто думает, что знает ответ, бонус-раунд: как сделать так, чтобы вывел оба раза alpha2, и почему он это сделает?