Generowanie klas za pomocą list typów - incomplete type is not allowed

0

Uczę się TMP w C++ i jestem na etapie rekurencyjnego generowania klas za pomocą list typów. Taki koncept jest przedstawiony między innymi w książce "Modern Design in C++" Andrei Alexandrescu no i niby zdefiniowałem listę typów oraz szablon, który ma mi te klasy generować. Niemniej jednak przy próbie deklaracji obiektu o określonym typie wywala mi błąd:

  incomplete type is not allowed 

oraz

Error	C2079     'obj' uses undefined class 'GenScatterHierarchy<TypeList<T,TypeList<std::basic_string<char,std::char_traits<char>,std::allocator<char>>,TypeList<double,make<>::type>>>,Holder>'

Co może być tego przyczyną? Czego mi brakuje, aby kompilator wygenerował mi hierarchię klas?

Kompiluje za pomocą MSVC na Visual Studio 2017.

Oto kod:

Lista typów:


struct null_t {};

template <typename T, typename U>
struct TypeList {
	using head = T;
	using tail = U;
};

template <typename ... Ts> struct make;

// Case: Normal recursion. Consume one type per call.
template <typename T, typename ... REST>
struct make<T, REST...> {
	using type = TypeList<T, typename make<REST...>::type>;
};

// Case: Recursion abort, because the list of types ran empty
template <>
struct make<> { using type = null_t; };

template <typename ... Ts>
using make_t = typename make<Ts...>::type;

Szablon generujący hierarchię:

template <typename TypeList, template<class> typename Unit>
class GenScatterHierarchy;

template <typename T1, typename T2, template <class> typename Unit>
class GenScatterHierarchy<TypeList<T1,TypeList<T2, null_t>>, Unit>
	: public GenScatterHierarchy<T1, Unit>
	, public GenScatterHierarchy<T2, Unit>
{

};

template <typename AtomicType, template <class> typename Unit>
class GenScatterHierarchy
	:public Unit<AtomicType>
{

};

template<template<class> typename Unit>
class GenScatterHierarchy<null_t, Unit>
{

}; 

No i main:

template <class T>
struct Holder {
	T value_t;
};

using GeneratedType = GenScatterHierarchy<make_t<int, std::string, double>, Holder>;

int main() 
{
	GeneratedType obj; // tu błąd

	system("pause");
	return 0;
}
3

GCC i Clang budują poprawnie, więc możliwe że winny jest kompilator MS (rzuciłem okiem i też nie wydaje mi się nic źle, poza stosowaniem implementacji sprzed 2 dekad). Ale jest jedno ale: książka Alexandrescu jest fantastyczna, ale jeśli chodzi o konkretne rozwiązania jest przestarzała. C++11, 14, 17 wprowadziły gigantyczne zmiany w metaprogramowaniu, i Modern C++ Design jest modern tylko w meta/abstrakcyjnym sensie. Nie powinna służyć za przykład implementacji.

2

W C++11 gcc 10.0.1, kod kompiluje się bez błędów, chociaż z ostrzeżeniami - https://wandbox.org/permlink/2iEekrtX1QpfiPMP
Jak zmienisz na C++17, to znikną także ostrzeżenia.

2

Kompiluje się na wszystkim, na MSVC też:
https://godbolt.org/z/NSMPhW

0

Ok to przeniosę się na inny kompilator, pewnie nadal zostanę przy msvc, ale teraz 2019, będzie najszybciej.

GCC i Clang budują poprawnie, więc możliwe że winny jest kompilator MS (rzuciłem okiem i też nie wydaje mi się nic źle, poza stosowaniem implementacji sprzed 2 dekad). Ale jest jedno ale: książka Alexandrescu jest fantastyczna, ale jeśli chodzi o konkretne rozwiązania jest przestarzała. C++11, 14, 17 wprowadziły gigantyczne zmiany w metaprogramowaniu, i Modern C++ Design jest modern tylko w meta/abstrakcyjnym sensie. Nie powinna służyć za przykład implementacji.

Moje wydanie z 2005 więc faktycznie modern tylko w nazwie. Sam jeszcze nie jestem dobrze obeznany w najnowszych standardach jeśli chodzi o metaprogramowanie. Co byś zatem zmienił w tym kodzie, albo jakie najważniejsze kwestie związane z metaprogramowaniem jest dobrze znać?

0

Ok wiem już, problem był w złym rozlokowaniu deklaracji i definicji po plikach. Jak wszystko wrzuciłem do maina to się skompilowało.

1 użytkowników online, w tym zalogowanych: 0, gości: 1