Chcę zaimplementować cechę typu has_no_duplicates<...>
, która jest oceniana na std::true_type
, jeśli lista typów variadic nie ma duplikatów.Użycie `void_t` do wykrycia błędów wielokrotnego powtarzania typu
static_assert(has_no_duplicates<int, float>{}, "");
static_assert(!has_no_duplicates<float, float>{}, "");
Załóżmy, dla zakresu tego pytania, że chcę to zrobić przy użyciu wielu dziedziczenia.
Gdy klasa dziedziczy z tego samego typu więcej niż jeden raz, pojawia się błąd.
template<class T>
struct type { };
template<class... Ts>
struct dup_helper : type<Ts>... { };
// No errors, compiles properly.
dup_helper<int, float> ok{};
// Compile-time error:
// base class 'type<float>' specified more than once as a direct base class
dup_helper<float, float> error{};
Przypuszczałem Mogłam stosować void_t
do „wykrywania” ten błąd, ale nie mogłem realizować roztwór roboczy following the code samples from cppreference.
To co próbowałem:
template<class, class = void>
struct is_valid
: std::false_type { };
// First try:
template<class T>
struct is_valid<T, std::void_t<decltype(T{})>>
: std::true_type { };
// Second try:
template<class T>
struct is_valid<T, std::void_t<T>>
: std::true_type { };
Na moim trzecim razem, próbowałem opóźniając ekspansję dup_helper<...>
użyciu klasy otoki, które miały dup_helper
jako parametr szablonu szablonu, jak wrapper<dup_helper, ...>
i rozszerzoną go wewnątrz void_t
.
Niestety, wszystkie moje próby spowodowały, że wspomniany błąd zawsze uniemożliwia kompilację.
Zakładam, że ten typ błędu nie jest wykrywany jako "niepowodzenie substytucji", ale chciałbym potwierdzić.
Jest to rodzaj błędu właściwie niemożliwe do wykrycia za pomocą void_t
? (Czy zawsze spowoduje to awarię kompilacji?)
Czy istnieje sposób na wykrycie tego błędu bez kompilacji? (Lub sposób obejścia inny niż void_t
, który nadal wykorzystuje "sztuczkę wielokrotnego dziedziczenia")?
Nie sądzę, można zrobić, że praca z wieloma dziedziczenia. Problem polega na tym, że nie jest to deklaracja 'dup_helper', która powoduje błąd, ale jego definicję (jeśli się nie mylę). –
Caninonos
@Caninonos Teoretycznie Vittorio było instancją 'T' w' decltype (T {}), a następnie otrzymywało typ. Vittorio miał nadzieję, że 'T {}' wygeneruje błąd, ponieważ faktyczna instrukcja 'T {}' jest błędem, nawet jeśli wynikowy typ nie jest. – Yakk
@Aakk, ale 'T {}' wymaga, aby kompilator zdefiniował 'T', a błąd znajduje się w jego definicji. To trochę tak, jak próbowanie błędu występującego w ciele funkcji szablonowej (zamiast końcowego argumentu typ/noexcept specifier/default template) i próby "złapania" go za pomocą sfinae, nie sądzę, że jest to możliwe (Nie wiem dokładnie, co mówi norma, ale nadal). (również, aby opublikować "rozwiązanie" z wieloma dziedziczeniami, istnieje [to] (http://ideone.com/oT20iI), jest to całkowicie niewiarygodne, ponieważ opiera się na EBO i rozmiarze pustej klasy, więc nie " t use it) – Caninonos