... не понимаю предупреждение, которое они делают о свисающей ссылке
::max(s1, s2, s3)
использует template<typename T> T const& max (T const& a, T const& b, T const& c)
, возвращая ссылку
Если определение template<typename T> T const& max (T const& a, T const& b, T const& c)
будет изменено на:
template<typename T>
T const& max (T const& a, T const& b, T const& c)
{
return (a > b) ? ((a > c) ? a : c)
: ((b > c) ? b : c);
}
, проблем не возникнет, поскольку у него уже есть ссылки.
Но с ::max(s1, s2, s3)
T равно const char*
, поэтому в max (max(a,b), c)
max равно char const* max (char const* a, char const* b)
, чья не возвращает ссылку, из-за чего компилятор сохраняет результат char const* max (char const* a, char const* b)
во временной переменной в стеке и возвращает ссылкук этой временной переменной, производящей ваше сообщение и связанную проблему.Это похоже на выполнение int & f() { int v = 0; return v; }
за исключением того, что временная переменная создается самим компилятором.
Конечно, проблема исчезает с template<typename T> T const max (T const& a, T const& b, T const& c)
(возвращая значение, а не ссылку), потому что значение возвращаетсяchar const* max (char const* a, char const* b)
может быть возвращено напрямую.
Примечание для ::max(7, 42, 68)
проблем нет, поскольку max в max (max(a,b), c)
равно template<typename T> T const& max (T const& a, T const& b)
, что возвращает ссылку.
Чтобы продолжить возвращать ссылку в другом случае, вы можете специализировать max для char *
, например:
// maximum of two C-strings (call-by-value)
template<>
char const* const & max (char const* const & a, char const* const & b)
{
return std::strcmp(b,a) < 0 ? a : b;
}
или определить его как
char const* const & max (char const* const & a, char const* const & b)
{
return std::strcmp(b,a) < 0 ? a : b;
}
, который возвращает ссылку версиис тремя параметрами можно использовать без необходимости использовать временную переменную и возвращать ссылку на нее.
(Лично я предпочитаю специализацию, потому что это кажется естественным иметь шаблонную версию)
#include <cstring>
#include <iostream>
// maximum of two values of any type (call-by-reference)
template<typename T>
T const& max (T const& a, T const& b)
{
return b < a ? a : b;
}
// MODIFIED
// maximum of two C-strings (call-by-value)
template<>
char const* const & max (char const* const & a, char const* const & b)
{
return std::strcmp(b,a) < 0 ? a : b;
}
// maximum of three values of any type (call-by-reference)
template<typename T>
T const& max (T const& a, T const& b, T const& c)
{
return max (max(a,b), c); // error if max(a,b) uses call-by-value
}
int main ()
{
auto m1 = ::max(7, 42, 68); // OK
char const* s1 = "frederic";
char const* s2 = "anica";
char const* s3 = "lucas";
auto m2 = ::max(s1, s2, s3); // run-time ERROR
std::cout << m2 << std::endl; // << ADDED TO CHECK
}
Компиляция и исполнение:
pi@raspberrypi:/tmp $ g++ -pedantic -Wall -Wextra s.cc
s.cc: In function ‘int main()’:
s.cc:28:8: warning: unused variable ‘m1’ [-Wunused-variable]
auto m1 = ::max(7, 42, 68); // OK
^~
pi@raspberrypi:/tmp $ ./a.out
lucas