У меня есть шаблон variadic, который наследует от всех аргументов шаблона:
template <typename... Ts>
struct derived : Ts...
{
};
Я также хотел бы иметь возможность для выражения типа "существующий derived
с добавленными аргументами шаблона". Моя попытка это:
// Do not ODR-use (goes in namespace impl or similar)!
template<class ... NewInputs, class ... ExistingInputs>
auto addedHelper(const derived<ExistingInputs...>&)
-> derived<ExistingInputs..., NewInputs...>;
template<class ExistingInput, class ... NewInputs>
using Added = decltype(addedHelper<NewInputs...>(std::declval<ExistingInput>()));
В качестве простого примера Added<derived<A, B>, C>
должны быть derived<A, B, C>
. Я использую вспомогательную функцию для вывода аргументов шаблона из первого пакета параметров.
Моя проблема: по какой-то причине я могу использовать это успешно с неполными типами, если derived
была заранее объявлена, но не если она была определена.
Почему этот код не компилируется :
#include <utility>
template <typename... Ts>
struct derived : Ts...
{};
template<class ... NewInputs, class ... ExistingInputs>
auto addedHelper(const derived<ExistingInputs...>&)
-> derived<ExistingInputs..., NewInputs...>;
template<class ExistingInput, class ... NewInputs>
using Added = decltype(addedHelper<NewInputs...>(std::declval<ExistingInput>()));
struct A;
struct B;
struct C;
// Goal: This forward declaration should work (with incomplete A, B, C).
auto test(derived<A, B> in) -> Added<decltype(in), C>;
struct A {};
struct B {};
struct C {};
void foo()
{
auto abc = test({});
static_assert(std::is_same_v<decltype(abc), derived<A, B, C>>, "Pass");
}
Принимая во внимание, что этот код компилируется :
#include <utility>
template <typename... Ts>
struct derived;
template<class ... NewInputs, class ... ExistingInputs>
auto addedHelper(const derived<ExistingInputs...>&)
-> derived<ExistingInputs..., NewInputs...>;
template<class ExistingInput, class ... NewInputs>
using Added = decltype(addedHelper<NewInputs...>(std::declval<ExistingInput>()));
struct A;
struct B;
struct C;
// Goal: This forward declaration should work (with incomplete A, B, C).
auto test(derived<A, B> in) -> Added<decltype(in), C>;
template <typename... Ts>
struct derived : Ts...
{};
struct A {};
struct B {};
struct C {};
void foo()
{
auto abc = test({});
static_assert(std::is_same_v<decltype(abc), derived<A, B, C>>, "Pass");
}
Для удобства, здесь оба случая одновременно (комментарий in/out #define FORWARD_DECLARED
): https://godbolt.org/z/7gM52j
Я не понимаю, как код мог стать незаконным, заменив предварительное объявление соответствующим определением (в противном случае это было бы позже).