2015-05-12 25 views
8
#include <string> 
#include <iostream> 
#include <tuple> 
#include <utility> 


template<typename... T> struct test { 

    using args_type = std::tuple<T...>; 

    args_type x; 

    template<std::size_t... I> 
    void callme(std::index_sequence<I...>) { 
     int _[] = {(std::get<I>(x).std::tuple_element<I, args_type>::type::~type(), true)...}; 
    } 
}; 

int main() { 
} 

Komunikat o błędzie jestDlaczego kompilator Clang ++ nie może skompilować następującego kodu szablonu variadic?

clang-3.7 -std=gnu++1y -Wc++14-extensions test.cpp 
test.cpp:15:56: error: expected ')' 
     int _[] = {(std::get<I>(x).std::tuple_element<I, args_type>::type::~type(), true)...}; 
                ^
test.cpp:15:20: note: to match this '(' 
     int _[] = {(std::get<I>(x).std::tuple_element<I, args_type>::type::~type(), true)...}; 
       ^
1 error generated. 

Ten sam kod wydaje się skompilować dobrze z G ++ 4.9.2. Nie mogłem znaleźć jeszcze żadnego odpowiedniego zgłoszenia błędu na stronie Clang.

+1

Skąd ta kopia brzękiem 3,7 pochodzą? Najnowsza wersja LLVM to tylko 3,6. –

+1

@ BillLynch svn. – Columbo

+1

Czy kompiluje się z 3.6? – Qix

Odpowiedz

10

wydaje się być bug Clang, chociaż wyszukiwanie takich pseudo-destructor nazw jest prawdopodobnie uszkodzona i przedmiotem otwartych kwestii CWG, konkretnie 555 i 399.

Znaczący nieco wzoru ekspansji jest

std::get<I>(x).std::tuple_element<I, args_type>::type::~type() 

Tutaj nieco pomiędzy . i () jest pseudo destructor nazwa; Nazwa wykwalifikowany wyszukiwarkę, ustala, że ​​

Jeżeli pseudo destructor nazwa (5.2.4) zawiera zagnieżdżone-NAME specyfikator, się typu nazwa S są wyglądała jako typów w zakres określony przez specyfikator nazwy zagnieżdżonej . Podobnie w kwalifikowanej ID formy:

                zagnieżdżone nazwa-specyfikator opcjonalnie   klasy nazwa:: ~klasy nazwa

druga nazwa nazwa klasy jest wyświetlana w tym samym zakresie co pierwsza.

tj. type jest wyszukiwane w std::tuple_element<I, args_type>, gdzie znajduje się w odniesieniu do pewnego typu. Zauważ, że nazwa-klasy jest gramatyczną nazwą dla identyfikatorów (i sic-template-id s) i nie musi odnosić się do rzeczywistej klasy. std::get<I>(x).std::tuple_element<I, args_type>::type::~type następnie odnosi się do destruktora z type.

Obejście z funkcji pomocniczej:

template <typename T> 
void destroy(T& p) {p.~T();} 

template<typename... T> struct test { 
    using args_type = std::tuple<T...>; 

    args_type x; 

    template<std::size_t... I> 
    void callme(std::index_sequence<I...>) { 
     int _[] = {(destroy(std::get<I>(x)), 0)...}; 
    } 
}; 
+0

Chciałbym złożyć raport. To dziwne. – Qix

+1

Specyfikacja wyszukiwania nazwy destruktora jest różnego rodzaju pomieszane. Jest co najmniej jeden długotrwały problem z tym związany. –

+0

@ T.C. Właśnie zdałem sobie sprawę, jak bardzo jest to dziwne. – Columbo

0

ciekawe, hstong od IBM mentioned w coupleworkarounds które działają lepiej.

int _[] = {(std::get<I>(x).::std::tuple_element<I, args_type>::type::~type(), true)...}; 

lub

int _[] = {(std::get<I>(x).std::template tuple_element<I, args_type>::type::~type(), true)...}; 
Powiązane problemy