Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > de.comp.lang.iso-c++ > #2057 > unrolled thread
| Started by | Stefan Reuther <stefan.news@arcor.de> |
|---|---|
| First post | 2017-07-19 18:51 +0200 |
| Last post | 2017-08-13 03:12 -0700 |
| Articles | 5 — 3 participants |
Back to article view | Back to de.comp.lang.iso-c++
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
| From | Stefan Reuther <stefan.news@arcor.de> |
|---|---|
| Date | 2017-07-19 18:51 +0200 |
| Subject | Overloading-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]
| From | Florian Weimer <fw@deneb.enyo.de> |
|---|---|
| Date | 2017-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]
| From | Stefan Reuther <stefan.news@arcor.de> |
|---|---|
| Date | 2017-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]
| From | SG <s.gesemann@gmail.com> |
|---|---|
| Date | 2017-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]
| From | SG <s.gesemann@gmail.com> |
|---|---|
| Date | 2017-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