5

Nach einem großen Artikeln lesen True Story: Efficient Packing ich versuchte, von mir zu implementieren Tupel als Übung:Call-Funktion ist nicht eindeutig, wenn irrelevant Typ als Alias ​​definiert

#include <type_traits> 
#include <utility> 
#include <functional> 

template< std::size_t I, typename T > 
struct tuple_leaf { T value; }; 

template< std::size_t I, typename T > 
T & get(tuple_leaf< I, T > & leaf) 
{ return leaf.value; } 

template< typename Is, typename ...Ts > 
struct tuple_base; 

template< std::size_t ...Is, typename ...Ts > 
struct tuple_base< std::index_sequence<Is...>, Ts... > 
    : tuple_leaf< Is, Ts >... 
{ 
    using tuple_base_t = tuple_base; 
    template< typename ...Args, typename = std::enable_if_t< (sizeof...(Ts) == sizeof...(Args)) > > 
    tuple_base(Args &&... args) 
     : tuple_leaf< Is, Ts >{std::forward<Args>(args)}... 
    { ; } 
}; 

#if 0 
template< typename ...Ts > 
struct tuple 
    : tuple_base< std::index_sequence_for<Ts...>, Ts... > 
{ 
    using tuple_base_t = typename tuple::tuple_base_t; 
    using tuple_base_t::tuple_base_t; 
    using tuple_base_t::operator = ; 
}; 
#else 
// terse 
template< typename ...Ts > 
using tuple = tuple_base< std::index_sequence_for<Ts...>, Ts... >; 
#endif 

template< typename ...Args > 
tuple< Args &&... > 
forward_as_tuple(Args &&... args) 
{ return {std::forward<Args>(args)...}; } 

#include <tuple> 

int 
main() 
{ 
    tuple<int> t(1); 
    auto f = forward_as_tuple(t); 
    (void)f; 
    return 0; 
} 

Live example

Nach der Implementierung von forward_as_tuple mir entscheiden, Ändern Sie die Definition von tuple Typ von Klassenvorlage bis Alias-Vorlage von seiner Basisklasse Vorlage, weil alles, was ich brauche von der Teilung in Klasse tuple selbst und seine Implementierung Klasse tuple_base ist nur std::index_sequence_for für variadic Vorlagentyp Parameter pack - Alias-Vorlage ist genau das geeignete Werkzeug für diesen Zweck. Nachdem ich, dass ich einen Fehler (#if 0 Fall):

error: call to 'forward_as_tuple' is ambiguous

Es sieht für mich seltsam, denn alias Vorlage nichts tut, und auf der anderen Seite forward_as_tuple für Typen aus dem gleichen Namensraum genannt - ich hatte gehofft, dass ADL sollte für den obigen Fall sicher funktionieren.

Wie erklärt man den Unterschied zwischen #if 1 und #if 0 Versionen des Codes?

+0

'std :: index_sequence_for' wird zu einem Typvorlagenargument vom Typ des Arguments eines Funktionsaufrufs, so dass' std' von ADL untersucht wird. Übrigens. Sie erhalten den gleichen Fehler, wenn Sie 'tuple ' direkt –

+0

@PiotrSkotnicki Subtilen Moment verwenden. Ich denke immer daran, dass ADL nur für Funktionsargumenttypen, aber auch für Vorlagenparameter ist. – Orient

+0

@PiotrSkotnicki 'tuple_base , int>>, tuple_base , int>>' ist das Funktionsargument. 'std :: index_sequence_for' ist tief drin. I.e. Es ist kein Top-Template-Name. Ist es wichtig? – Orient

Antwort

3

Adl bewirkt, dass Nachschlagevorgänge in dem übergebenen Typ und den Vorlagenargumenten des Typs übergeben werden.

Der Tupel-Nichtaliasname hat seine Typen und selbst als Orte, an denen nach ADL gesucht werden soll.

Der Tupel-Alias-Fall hat eine std::index_sequence in seiner Vorlage Argumentliste. Dies führt dazu, dass std::forward_as_tuple zusätzlich zu Ihrer forward_as_tuple berücksichtigt werden. Sie sind gleichermaßen gute Übereinstimmungen, und Zweideutigkeit tritt auf.

Wie @Piotr in den Kommentaren oben erwähnt, zeigt tuple<std::string> dieses Problem auch im Nicht-Alias-Fall.