Простой вопрос по С++

bleyman

Код!
#include <iostream>

using namespace std;

template <class T>
void alpha(T&,T&)
{
cout<<"alpha1"<<endl;
}

void alpha(char*, char*)
{
cout<<"alpha2"<<endl;
}


int main(int argc, char* argv[])
{
alpha("February","September");
alpha("June","July");
return 0;
}

Что выведет и почему?
Для тех, кто думает, что знает ответ, бонус-раунд: как сделать так, чтобы вывел оба раза alpha2, и почему он это сделает?

agent007new

По-хорошему, этот код не должен компилироваться, т.к. не существует неявного преобразования от const char* до char* (для выбора второго варианта) и невозможно забиндить ссылку на rvalue (для выбора первого варианта когда длина строк различна. В студии косяк

Dasar

По-хорошему, этот код не должен компилироваться,
Comeau тоже сожрал без ошибок
http://www.comeaucomputing.com/tryitout/

bleyman

$ g++ --version
g++ (GCC) 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)
Вообще действительно очень загадочная хрень! По всей видимости строковые константы всё-таки можно приводить к char* из соображений совместимости с С. И почему-то к char& (тоже неконстантным). Но почему char& ему нравится больше char* в случае одинаковой длины... А! Наверное, он подставляет в темплейт char* вместо T, то есть получается как бы char*&, а точнее - char[N]&. Хм. Ну а зачем он вообще длину учитывает, она где-нибудь умеет проявляться?

slonishka

Ну а зачем он вообще длину учитывает, она где-нибудь умеет проявляться?
(const)? char [N] для разных N — это разные типы, если я не ошибаюсь.
соответственно, в первом случае сработает шаблон (T = const char [N] а во втором придется применить "нехорошее" преобразование.
(мой компилятор выдает ворнинг).

slonishka

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

какой же ебанутый все-таки язык. =)
записал пример в блокнотик.

Andbar

какой же ебанутый все-таки язык. =)
Не согласен. Без этого было бы не возможно упрощение синтаксиса для функций c `_s`, т.е. шаблоны вида:
template<N>inline errno_t strcpy_s(char dst[N], char *src){return strcpy_s(dst, N, src);}

slonishka

это идиотизм, а не упрощение.
и я предполагаю, что ты, не увидев любимого компилятора среди указанных мною,
решил специально своей глупостью меня позлить. =)
ну. по крайней мере тебе ничего не грозит в ответ.
злить меня куда более безопасно, чем пользоваться функциями с `_s`.

Andbar

злить меня куда более безопасно, чем пользоваться функциями с `_s`.
что опасного в этих функциях, не объяснишь? Помимо того, что для компилирования под гцц приходится добавлять к проекту несколько файлов?
Но кое с чем соглашусь. Непонятно, зачем отличать строки с разной длиной на уровне RTTY. В смысле, не понятно, где это может пригодиться.

slonishka

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

Andbar

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

procenkotanya

Ну а зачем он вообще длину учитывает, она где-нибудь умеет проявляться?
sizeof("September") == 10

agent007new

Вообще действительно очень загадочная хрень! По всей видимости строковые константы всё-таки можно приводить к 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
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. ]
Оказывается, что все-таки можно приводить строковые литералы к char*, поэтому программа правильно делает, что компилируется. Осталось разобраться, почему шаблон во втором случае является более предпочтительным

kokoc88

почему шаблон во втором случае является более предпочтительным
Потому что не требует приведения типов.

agent007new

Потому что не требует приведения типов.
Нет, приведение здесь выполняется, но по тому же пункту, что я запостил раньше, приведение к const char* больее приоритетное, чем к char*, поэтому и выбирается шаблон из-за точного соответствия.
Стандарт 14.8.3.6
template<class T> void f(T); // declaration
void g
{
f("Annemarie"); // call of f<const char*>
}

kokoc88

Нет, приведение здесь выполняется, но по тому же пункту, что я запостил раньше, приведение к const char* больее приоритетное, чем к char*, поэтому и выбирается шаблон из-за точного соответствия.
Не понял тебя. В шаблоне приведения типов нет, тип T как был char const[N], таким и остаётся.

agent007new

Не понял тебя. В шаблоне приведения типов нет, тип как был char const[N], таким и остаётся.
Да, я наврал. Т.к. там ссылка, то приведения никакого нет. Если же ссылку убрать, то T будет - const char*, а не const char[5]

Anturag


#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;
}

slonishka

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

yolki


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"

tokuchu

думаю тут очень глубоко в спецификации зарыто что-то около "Implementation-defined behavior"
Может просто некоторые implementation не являются полностью standard compliant?

bleyman

Ой.
Продолжение банкета!
Если в оригинальном примере взять не void alpha(T&,T& а void alpha(T,T то теперь всегда резолвится темплейтный вариант... Причём если написать там ещё вывод typeid(T).name то в оригинале получается "char const [5]", а в модифицированном варианте - "char const *". Почему так?

pitrik2

Если в оригинальном примере взять не void alpha(T&,T& а void alpha(T,T то теперь всегда резолвится темплейтный вариант...
а если сюда же у второго варианта const прописать?
в изначальном const приводил к вызову второго всегда

Dasar

Почему так?
так потому что как только ты пишешь T, так сразу получается возможным преобразование к const char *, а оно более приоритетное, чем char *
зы
кстати когда длина одиннаковая там тоже тип получается const char *, а не char[N]?

Missi4ka

А почему ему меньше нравится приводить к const char* & в случае T&? Типа это менее приоритетно, чем просто const char*?

slonishka

кстати когда длина одиннаковая там тоже тип получается const char *, а не char[N]?
да (и мне это кажется странным).

milanadiana

Пора начинать расстреливать авторов языка. Самое главное для кодеров теперь не дай бог никогда не воспользоваться этой херотой! :grin: :grin: :grin: :grin:

Andbar

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]

Koty83

Но тогда можете объяснить тем, кто все еще в танке, чему равно T если выбирается шаблон от (T&, T&) в случае равных длин строк? const char*? Но почему тогда туда подставляется константа "abc", когда возможна только переменная?

Andbar

Но тогда можете объяснить тем, кто все еще в танке, чему равно T если выбирается шаблон от (T&, T&) в случае равных длин строк? const char*? Но почему тогда туда подставляется константа "abc", когда возможна только переменная?
Нет, T равно const char[N]

erotic

Код!
Воистину пути преобразований неисповедимы.
Оставить комментарий
Имя или ник:
Комментарий: