Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > de.comp.lang.iso-c++ > #2057 > unrolled thread

Overloading-Problem

Started byStefan Reuther <stefan.news@arcor.de>
First post2017-07-19 18:51 +0200
Last post2017-08-13 03:12 -0700
Articles 5 — 3 participants

Back to article view | Back to de.comp.lang.iso-c++


Contents

  Overloading-Problem Stefan Reuther <stefan.news@arcor.de> - 2017-07-19 18:51 +0200
    Re: Overloading-Problem Florian Weimer <fw@deneb.enyo.de> - 2017-07-19 21:37 +0200
      Re: Overloading-Problem Stefan Reuther <stefan.news@arcor.de> - 2017-07-21 20:09 +0200
        Re: Overloading-Problem SG <s.gesemann@gmail.com> - 2017-08-13 05:40 -0700
    Re: Overloading-Problem SG <s.gesemann@gmail.com> - 2017-08-13 03:12 -0700

#2057 — Overloading-Problem

FromStefan Reuther <stefan.news@arcor.de>
Date2017-07-19 18:51 +0200
SubjectOverloading-Problem
Message-ID<oko9n8.3qc.1@stefan.msgid.phost.de>
Hallo,

ich bin heute auf ein mir unerklärliches Overloading-Problem gestoßen.
Minimiert sieht das so aus:
----8<--------8<--------8<--------8<--------8<----
#include <string>

template<typename T>
class foo {
 public:
   foo()
      { }

   foo(const foo& f)   //1
      { m = f.m; }

   template<typename U>
   foo(U&& u)          //2
      { m = u; }

 private:
   T m;
};

void bar() {
   foo<std::string> a;
   foo<std::string> b(a); //3
}
----8<--------8<--------8<--------8<--------8<----

In Zeile //3 wählt der Compiler (z.B. g++-5.4.0 -std=c++11) den Overload
//2 und beschwert sich dann, dass er das keinen passenden
Zuweisungsoperator für 'm = u' findet.

> t.cpp: In instantiation of ‘foo<T>::foo(U&&) [with U = foo<std::__cxx11::basic_string<char> >&; T = std::__cxx11::basic_string<char>]’:
> t.cpp:22:24:   required from here
> t.cpp:14:11: error: no match for ‘operator=’ (operand types are ‘std::__cxx11::basic_string<char>’ and ‘foo<std::__cxx11::basic_string<char> >’)

Erwartet hätte ich, dass Overload //1 gewählt wird. Wenn ich //2
auskommentiere, ist das auch der Fall.

Gewohnt bin ich aus C++98, dass der Compiler gerade fürs Kopieren eines
Objektes einen Template-Konstruktor nicht einmal zur Kenntnis nimmt.

Wie bekomme ich das aufgelöst?


  Stefan

[toc] | [next] | [standalone]


#2059

FromFlorian Weimer <fw@deneb.enyo.de>
Date2017-07-19 21:37 +0200
Message-ID<87lgnkusk8.fsf@mid.deneb.enyo.de>
In reply to#2057
* Stefan Reuther:

> Erwartet hätte ich, dass Overload //1 gewählt wird. Wenn ich //2
> auskommentiere, ist das auch der Fall.

Für //1 fehlt aber das const, deswegen gewinnt offenbar //2.

> Gewohnt bin ich aus C++98, dass der Compiler gerade fürs Kopieren eines
> Objektes einen Template-Konstruktor nicht einmal zur Kenntnis nimmt.
>
> Wie bekomme ich das aufgelöst?

Man kann sicherlich etwas mit std::enable_if reißen.

Ich würde vermutlich das Overloading weglassen und die Spezialisierung
für foo mittels einer Trait-struct o.ä. erreichen.

[toc] | [prev] | [next] | [standalone]


#2061

FromStefan Reuther <stefan.news@arcor.de>
Date2017-07-21 20:09 +0200
Message-ID<oktn1k.4h4.1@stefan.msgid.phost.de>
In reply to#2059
Am 19.07.2017 um 21:37 schrieb Florian Weimer:
> * Stefan Reuther:
>> Gewohnt bin ich aus C++98, dass der Compiler gerade fürs Kopieren eines
>> Objektes einen Template-Konstruktor nicht einmal zur Kenntnis nimmt.
>>
>> Wie bekomme ich das aufgelöst?
> 
> Man kann sicherlich etwas mit std::enable_if reißen.
> 
> Ich würde vermutlich das Overloading weglassen und die Spezialisierung
> für foo mittels einer Trait-struct o.ä. erreichen.

Konkret soll das ein std::optional-Ersatz für C++98 bis 14 werden, die
Signaturen der Konstruktoren sind durch C++17 vorgegeben.

Ich hatte gehofft, dass das mit "Signaturen in ein Headerfile kopieren
und die paar nötigen Zeilen Code reinkopieren" abgeht - vor allem ohne
zusätzliche Dependencies. Ich fürchte, ich muss dann doch mal bei Boost
spicken gehen...


  Stefan

[toc] | [prev] | [next] | [standalone]


#2062

FromSG <s.gesemann@gmail.com>
Date2017-08-13 05:40 -0700
Message-ID<d7342ac4-b534-47c0-bc5c-53acbb788bd8@googlegroups.com>
In reply to#2061
Am Freitag, 21. Juli 2017 20:40:03 UTC+2 schrieb Stefan Reuther:
> 
> Konkret soll das ein std::optional-Ersatz für C++98 bis 14 werden, die
> Signaturen der Konstruktoren sind durch C++17 vorgegeben.
> 
> Ich hatte gehofft, dass das mit "Signaturen in ein Headerfile kopieren
> und die paar nötigen Zeilen Code reinkopieren" abgeht - vor allem ohne
> zusätzliche Dependencies. Ich fürchte, ich muss dann doch mal bei Boost
> spicken gehen...

Du hast eine Bemerkung übersehen:

  template<class U = T> EXPLICIT constexpr optional(U&& v);

  [...] This constructor shall not participate in overload resolution
  unless is_constructible_v<T,U&&> is true, is_same_v<U, in_place_t>
  is false, and is_same_v<optional<T>, decay_t<U>> is false. [...]

Das "shall not participate in overload resolution" wird üblicherweise
via SFINAE implementiert, also etwa so:

  template<class U = T
    ,class = typename std::enable_if<
        std::is_constructible<T,U&&>::value &&
        !std::is_same<U, in_place_t>::value &&
        !std::is_same<optional<T>,
                      typename std::decay<U>::type >::value
    >::type
  > constexpr optional(U&& v)
  [...]

Diese "Forwarding-Referenz" zusammen mit den type traits gibt's
natürlich erst ab C++11.

SG

[toc] | [prev] | [next] | [standalone]


#2063

FromSG <s.gesemann@gmail.com>
Date2017-08-13 03:12 -0700
Message-ID<e2a1d1b0-b207-4bbc-8456-06b2b5d5126c@googlegroups.com>
In reply to#2057
Am Mittwoch, 19. Juli 2017 19:00:05 UTC+2 schrieb Stefan Reuther:
> 
> template<typename T>
> class foo {
>  public:
> 
>    foo(const foo& f)   //1
> 
>    template<typename U>
>    foo(U&& u)          //2
> 
> };
> 
> void bar() {
>    foo<std::string> a;
>    foo<std::string> b(a); //3
> }
> ----8<--------8<--------8<--------8<--------8<----
> 
> In Zeile //3 wählt der Compiler (z.B. g++-5.4.0 -std=c++11) den Overload
> //2 und beschwert sich dann, dass er das keinen passenden
> Zuweisungsoperator für 'm = u' findet.
> 
> Erwartet hätte ich, dass Overload //1 gewählt wird. Wenn ich //2
> auskommentiere, ist das auch der Fall.
> 
> Gewohnt bin ich aus C++98, dass der Compiler gerade fürs Kopieren eines
> Objektes einen Template-Konstruktor nicht einmal zur Kenntnis nimmt.

Das war aber noch nie so.

> Wie bekomme ich das aufgelöst?

Wegen //3 wird bei //2 der Parameter U mit foo<string>& deduziert und
ist ein besserer Match als //1, weil da bei //1 noch ein const dazu
kommen würde.

Eine Möglichkeit wäre, dem zweiten Konstruktor quasi einen Namen
geben. Das findest Du so so ähnlich auch bei std::pair. Das Ding hat
nämlich folgenden Konstruktor ab C++11:

   template< class... Args1, class... Args2 >
   pair( std::piecewise_construct_t,
         std::tuple<Args1...> first_args,
         std::tuple<Args2...> second_args );

Aufrufen tut man den dann so:

   pair<T,U> x (std::piecewise_construct,
      std::forward_as_tuple(...),
      std::forward_as_tuple(...) );

Der erste "dummy" Parameter ist quasi der Name des Konstruktors.

Du kannst aber auch sowas schreiben, wenn Du magst:

    template<typename U
       ,class = typename std::enable_if<
          std::is_constructible<T,U&&>::value
       >::type
    >
    foo(U&& u)
    : m(std::forward<U>(u))
    {}

(Bei dem type-trait bin ich mir gerade nicht sicher. Habe ich
jetzt nicht extra nachgeguckt)

[toc] | [prev] | [standalone]


Back to top | Article view | de.comp.lang.iso-c++


csiph-web