2016-12-07 10 views
15

rozważ kod wklejony poniżej. Zdefiniowałem bardzo prostą klasę, dla której kompilator generuje domyślny przewodnik dedukcji, dzięki czemu można go skonstruować bez jawnych argumentów szablonu. Jednakże odliczenie szablon argumentem nie pracę na budowie obiektu od prostego szablonu alias który tylko przekazuje bezpośrednio do klasy docelowej:Odliczanie argumentów szablonu klasy nie działa z szablonem aliasu

template< typename A, typename B > 
struct Foo { 
    Foo(A const &a, B const &b) 
      : a_(a), b_(b) 
    { } 

    A a_; 
    B b_; 
}; 

template< typename A, typename B > 
using Bar = Foo<A, B>; 

auto foobar() { 
    Foo r{1, 2}; 
    Bar s{3, 4}; 
    // ../src/geo/vector_test_unit.cpp: In function 'auto foobar()': 
    // ../src/geo/vector_test_unit.cpp:16:6: error: missing template arguments before 's' 
    // Bar s{3, 4}; 
    //  ^
    return 1; 
} 

Jak widać z komentarzem powyższym kodzie, g ++ daje mi błąd dotyczący używania szablonu aliasingu bez argumentów szablonu. Miałem nadzieję, że w takim przypadku zostanie odesłany szablon.

Tak, moje pytanie: Czy jest to przez wyraźny projekt obecnego sformułowania wniosku o odrzucenie argumentu szablonu klasy? Czy jest to niedokończona funkcja lub błąd w bieżącej implementacji funkcji g ++? I byłoby to raczej pytanie dla autorów wniosku, lub dla Komitetu C++ ISO, ale jeśli któryś z nich to widzi: Czy byłoby pożądane, aby ostateczne sformułowanie cechy obejmowało umożliwienie używania szablonów aliasów, takich jak ten, do wygenerować dla nich niejawne przewodniki?

Rozumiem, że ponieważ szablony aliasów mogą mieć dowolne parametry szablonu, kompilator może nie zawsze mieć możliwość wyprowadzenia argumentów szablonu klasy docelowej, ale w takim przypadku spodziewałbym się, że kompilator będzie w stanie w taki sam sposób, jak może bezpośrednio dla klasy docelowej.

Buduję z gcc zbudowany z głowy zaledwie kilka dni temu, używając --std=c++1z. Kompletna informacja o wersji: gcc version 7.0.0 20161201 (experimental) (Homebrew gcc HEAD- --with-jit)

Odpowiedz

21

To była funkcja, którą rozważaliśmy przy formułowaniu propozycji, ale ostatecznie została przerwana, ponieważ nie mieliśmy jeszcze wystarczająco dobrego projektu. W szczególności istnieją pewne subtelności dotyczące sposobu wybierania i przekształcania przewodników odliczeń z szablonów aliasów do przewodników dedukcji dla szablonu aliasu. Istnieją również otwarte pytania, jak się zachować, jeśli szablon aliasu nie jest prostym aliasem dla innego szablonu. Kilka przykładów:

template<typename T> struct Q { Q(T); };  // #1 
template<typename T> struct Q<T*> { Q(T); }; // #2 
template<typename T> using QP = Q<T*>; 
int *x; 
Q p = x; // deduces Q<int*> using #1, ill-formed 
QP q = x; // deduces Q<int*> using #1, or 
      // deduces Q<int**> using #2? 

template<typename T> Q(T) -> Q<T>; // #3 
QP r = x; // can we use deduction guide #3 here? 

template<typename T> Q(T*) -> Q<T**>; // #4 
int **y; 
QP s = y; // can we use deduction guide #4 here? 

template<typename T> struct A { typedef T type; struct Y {}; }; 
template<typename T> using X = typename A<T>::type; 
template<typename T> using Y = typename A<T>::Y; 
X x = 4;   // can this deduce T == int? 
X y = A<int>::Y(); // can this deduce T == int? 

Istnieje godnej odpowiedzi na powyższe pytania, ale przeciwdziałanie im zwiększa złożoność i wydawało się korzystne, aby uniemożliwić odliczenie szablonów alias dla C++ 17 zamiast spieszyć coś wadliwy.

Przewiduję, że zobaczymy artykuł od Faisala z propozycją tej funkcji dla C++ 20.

+0

Zbudowuję i kompiluję przykładowy plik jeden po drugim, aby spróbować go zrozumieć stopniowo. Właśnie skompilowałem go używając tylko # 1, # 2 i linii 'int * x; Q p = x; '. Daje błąd, jak wskazałeś, chyba że usunę # 2 i ponownie skompiluję. Komunikat o błędzie z g ++ to "[...] błąd: nieprawidłowa konwersja z" int * "na" int "... Q p = x; ... uwaga: inicjalizacja argumentu 1 z 'Q :: Q (T) [z T = int]' wzorzec struktura Q {Q (T); }; '. Dla mnie wygląda na to, że próbujesz użyć # 2 zamiast # 1, tak jak powiedziałeś. Czego nie rozumiem? –

+1

@squidbidness Wiersz 'Q p = x;' dedukuje typ 'p' do' Q 'używający # 1 do odrzucenia argumentu szablonu klasy.Po wybraniu tego typu wnioskuje się, że 'Q ' powinno używać częściowej specjalizacji 'Q ', dedukując' T = int'. Na koniec próbuje wywołać konstruktor 'Q ' z parametrem typu 'int *', który nie działa, ponieważ jedyny konstruktor (inny niż domyślni/kopiuj/przenieś ctors) przyjmuje 'int'. –

+0

Dziękuję za wyjaśnienie. Częścią, która mnie myliła jest to, że mój model mentalny wydedukował typ "p" i wybrał specjalizację szablonu jako jeden i ten sam proces. Wskazywanie, że są to osobne kroki, pomaga mi znacznie lepiej to rozumieć. –

Powiązane problemy