user-defined conversions: could not deduce template argument
От: MuTPu4  
Дата: 06.12.05 16:52
Оценка:
Некоторое время назад на comp.lang.c++.moderated проскакивал вопрос, в котором автор приводил такой код:
#include<string>
#include<iostream>

class S
{
public:
  operator std::string(){return " ";}
};
 
int main()
{
  std::cout<<S(); // error! but should it be?
  return 0;
}


Я даже попытался избавиться от стандартной библиотеки, чтобы все было перед глазами (пример не минимальный, просто хотел не отходить далеко от библиотечных сигнатур и аргументов):
namespace m4
{
  template<
      typename value_t
    , typename char_traits_t = char
  >
  class StringHolder
  {};

  typedef StringHolder< char > my_string;

  template< typename value_t, typename char_traits_t >
  class OstreamHolder
  {};

  template< typename value_t, typename char_traits_t >
  void
  operator<<(
      OstreamHolder< value_t, char_traits_t > const &
    , StringHolder< value_t, char_traits_t > const &  //(1)
  )
  {}
}

class Convertible
{
  public:

    operator m4::my_string const( ) const
    {
      return( m4::my_string( ) );
    }
};

int main( void )
{
  ::m4::OstreamHolder< char, char >( ) << Convertible( );
}


Собственно, вопрос: почему не рассматривается мой m4::operator<<( ... ) при разрешении перегрузки? Причем, если (1) заменить на "StringHolder< char, char > const &" то все отлично.
Re: user-defined conversions: could not deduce template argu
От: lLPl  
Дата: 06.12.05 17:43
Оценка: 26 (2) +1
Здравствуйте, MuTPu4, Вы писали:
...

MTP>Собственно, вопрос: почему не рассматривается мой m4::operator<<( ... ) при разрешении перегрузки?

Для того чтобы был выбран Ваш operator<< должно произойти пользовательское преобразование типов.
Т.к. operator<< является шаблонным никаких преобразований, кроме тривиальных, при выводе аргументов шаблона, не происходит.

MTP> Причем, если (1) заменить на "StringHolder< char, char > const &" то все отлично.

В этом случае вывода аргументов для 2-го параметра функции шаблона не происходит и преобразование допустимо.
C++ можно выучить за 21 день! ...если дни — полярные.
Re[2]: user-defined conversions: could not deduce template a
От: lLPl  
Дата: 06.12.05 18:01
Оценка:
Вот упрощенный пример:
template<class T1, class T2>
struct A{};

template<class T1, class T2>
struct B
{

};


struct C
{
    operator B<int, short>()
    {
        return B<int, short>();
    }
};

template<class T1, class T2>
void operator<<(A<T1, T2> t1, B<T1, T2> t2)
{
}
/*
template<class T1, class T2>
void operator<<(T1 t1, T2 t2)
{
}*/

int main()
{
    A<int, short>() << C();    
    return 0;
}

Для того чтобы вывести аргументы T1 и T2 для 2-го параметра функции t2, должно совершиться преобразование,
что недопустимо.
При
...
A<int, short>() << B<int, short>();
...

все естественно работает.
А при
...
template<class T1, class T2>
void operator<<(A<T1, T2> t1, B<int, short> t2)
{
}
...

вывода аргументов нет, — преобразование разрешено, как для обычной нешаблонной функции.
C++ можно выучить за 21 день! ...если дни — полярные.
Re: user-defined conversions: could not deduce template argu
От: andrij Украина  
Дата: 06.12.05 18:05
Оценка: -1
On Tue, 06 Dec 2005 18:52:55 +0200, MuTPu4 <40559@users.rsdn.ru> wrote:

> Некоторое время назад на comp.lang.c++.moderated проскакивал вопрос, в котором автор приводил такой код:

>
> #include<string>
> #include<iostream>
>
> class S
> {
> public:
/*
етот оператор не работоспособен, ибо приведение к std::string() разрешено только експлисит:
   operator std::string(){return std::string(" ");}
*/
>   operator std::string(){return " ";}
> };
>int main()
> {
/*
   вивод для std::string в стрим не определьон, а оператора operator const char*()
   у std::string также нет, есть ф-ция член с_str():
   std::cout<< static_cast<std::string>(S()).c_str(); // так работает
*/
>   std::cout<<S(); // error! but should it be?
>   return 0;
> }
>

>
Posted via RSDN NNTP Server 1.9
make it simple as possible, but not simpler
Re[3]: user-defined conversions: could not deduce template a
От: NotImplemented США github.com/NotImplemented
Дата: 06.12.05 18:32
Оценка:
> Здравствуйте, lLPl, Вы писали:

Было бы неплохо подкреплять свои утверждения ссылками на авторитетный источник.
В вашем случае, кстати, аргументы могут быть выведены из типа A<int, short> аргумента оператора <<.
Re[4]: user-defined conversions: could not deduce template a
От: lLPl  
Дата: 06.12.05 18:40
Оценка:
Здравствуйте, NotImplemented, Вы писали:

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


NI>Было бы неплохо подкреплять свои утверждения ссылками на авторитетный источник.

NI>В вашем случае, кстати, аргументы могут быть выведены из типа A<int, short> аргумента оператора <<.

Я же в обоих своих постах указал, что говорю о 2-м аргументе функции.

В этом случае вывода аргументов для 2-го параметра функции шаблона не происходит и преобразование допустимо.


Для того чтобы вывести аргументы T1 и T2 для 2-го параметра функции t2, должно совершиться преобразование,
что недопустимо.

C++ можно выучить за 21 день! ...если дни — полярные.
Re[5]: user-defined conversions: could not deduce template a
От: lLPl  
Дата: 06.12.05 18:43
Оценка:
LP>Здравствуйте, NotImplemented, Вы писали:

NI>>В вашем случае, кстати, аргументы могут быть выведены из типа A<int, short> аргумента оператора <<.


А, или Вы о том, что они могут быть выведены из первого параметра и использованы для второго? Так не могут ведь!?
C++ можно выучить за 21 день! ...если дни — полярные.
Re[2]: user-defined conversions: could not deduce template a
От: Кодт Россия  
Дата: 06.12.05 18:57
Оценка:
Здравствуйте, andrij, Вы писали:

A>/*

A>етот оператор не работоспособен, ибо приведение к std::string() разрешено только експлисит:
A> operator std::string(){return std::string(" ");}
A>*/
Неправда. у std::string конструктор(char const*) имплицитный.
A>/*
A> вивод для std::string в стрим не определьон, а оператора operator const char*()
A> у std::string также нет, есть ф-ция член с_str():
A> std::cout<< static_cast<std::string>(S()).c_str(); // так работает
A>*/
Опять неправда. Строку можно выводить в поток напрямую, без .c_str().

#include <string>
#include <iostream>

std::string foo() { return "hello, world"; }

int main()
{
  std::cout << foo() << std::endl;
}
Перекуём баги на фичи!
Re[6]: user-defined conversions: could not deduce template a
От: lLPl  
Дата: 06.12.05 19:11
Оценка:
Здравствуйте, lLPl, Вы писали:

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


NI>>>В вашем случае, кстати, аргументы могут быть выведены из типа A<int, short> аргумента оператора <<.


Ладно, дошло, — я неправильно выразился.

Для того чтобы вывести аргументы T1 и T2 для 2-го параметра функции t2,...

Надо было сказать:
Для того чтобы произошла подстановка второго аргумента функции...
C++ можно выучить за 21 день! ...если дни — полярные.
Re: user-defined conversions: could not deduce template argu
От: Кодт Россия  
Дата: 06.12.05 19:17
Оценка: 2 (1)
Здравствуйте, MuTPu4, Вы писали:

Чуть более компактный код.
template<class T>
struct Src {};

typedef Src<int> SrcI;

struct LikeSrcI { operator SrcI() { return SrcI(); } };
struct LikeSrcT { template<class T> operator Src<T>() { return Src<T>(); } };

void dst1(SrcI) {}

template<class T>
void dst2(Src<T>) {}

int main()
{
template<class T>
void dst3(T, Src<T>) {}

int main()
{
  //                       ~~~~~~~~~~~~~~~~~~~~~~~ не компилируются
  LikeSrcI lsi; dst1(lsi); dst2(lsi); dst3(1,lsi);
  LikeSrcT lst; dst1(lst); dst2(lst); dst3(1,lsi);

  // всё компилируется
  SrcI     src; dst1(src); dst2(src); dst3(1,lsi);
}

Причина — именно в том, что неявные действия
— вывод типа шаблона
— приведение типа
— конструирование (кроме конструктора копирования)
можно делать в количестве "одна штука на аргумент".
(Явные — разумеется, сколько угодно).

А у тебя получилось неявный operator T() + неявное определение типа шаблона.
Было бы двойное приведение типов — тоже получил бы ошибку.

(Где-то в Стандарте об этом написано, но, к сожалению, текста под рукой нет).
Перекуём баги на фичи!
Re[2]: user-defined conversions: could not deduce template a
От: MuTPu4  
Дата: 07.12.05 16:06
Оценка:
Здравствуйте, Кодт, Вы писали:

Спасибо, вроде, разобрался.
lLPl наиболее точно назвал проблему, подробности я нашел в 14.8.2.1/3 и в книжке Вандервурда про шаблоны (II.11.4).

К>Чуть более компактный код.

Исправил/дополнил пример, может, кому будет интересно:

template<class T>
struct Src {};

typedef Src<int> SrcI;

struct LikeSrcI { operator SrcI() { return SrcI(); } };
struct LikeSrcT { template<class T> operator Src<T>() { return Src<T>(); } };
struct DeriveSrc : public SrcI {};

void dst1(SrcI) {}

template<class T>
void dst2(Src<T>) {}

template<class T>
void dst3(T, Src<T>) {}

int main()
{
  LikeSrcI lsi;
  dst1(lsi);
  dst2< int >(lsi);
//dst2(lsi);       //fail
//dst3(1,lsi);     //fail

  LikeSrcT lst;
  dst1(lst);
  dst2< int >(lsi);
//dst2(lst);       //fail
//dst3(1,lsi);     //fail

  SrcI src;
  dst1(src);
  dst2(src);
  dst3(1,src);

  DeriveSrc dsrc;
  dst1(dsrc);
  dst2(dsrc);
  dst3(1,dsrc);
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.