Частичное упорядочение в сочетании с параметром шаблона шаблона и шаблонами с переменными параметрами

У меня есть вопрос о специализации шаблонов в сочетании с переменными шаблонами и параметрами / аргументами шаблонных шаблонов.

Следующая маленькая программа компилируется с Clang 6.0.1 а также GCC 8.1.1 (Цель: x86_64-pc-linux-gnu).

#include <iostream>

struct IndexSlot3 {
    static constexpr std::size_t size = 3;
};

template<typename T_, typename... IndexSlots_>
struct Tensor {
    Tensor() { std::cout << "Order N picked" << std::endl; }
};
template<typename T_, typename IndexSlot0_>
struct Tensor<T_, IndexSlot0_> {
    Tensor() { std::cout << "Order 1 picked" << std::endl; }
};
template<typename T_, typename IndexSlot0_, typename IndexSlot1_>
struct Tensor<T_, IndexSlot0_, IndexSlot1_> {
    Tensor() { std::cout << "Order 2 picked" << std::endl; }
};

int main(int argc, char** argv) {
    Tensor<int, IndexSlot3> t1;
    Tensor<int, IndexSlot3, IndexSlot3> t2;
    Tensor<int, IndexSlot3, IndexSlot3, IndexSlot3> t3;

    return 0;
}

Скомпилировать команды:

clang++ -std=c++17 main.cpp -o main -Wall -Wpedantic
g++ -std=c++17 main.cpp -o main -Wall -Wpedantic

Запуск программы печатает

Order 1 picked
Order 2 picked
Order N picked

с обоими компиляторами, как и ожидалось.

Тем не менее, когда я распространяю вышеизложенное на следующую программу, где Tensor также принимает параметр шаблона шаблона, определяющий хранилище, Clang выбирает основной шаблон во всех трех случаях, в то время как GCC по-прежнему выбирает специализации.

#include <iostream>

struct IndexSlot3 {
    static constexpr std::size_t size = 3;
};

template<typename T_, std::size_t... sizes>
struct CArrayStorage {
    using Type = T_*;
};
template<typename T_, std::size_t size0_>
struct CArrayStorage<T_, size0_> {
    using Type = T_[size0_];
};
template<typename T_, std::size_t size0_, std::size_t size1_>
struct CArrayStorage<T_, size0_, size1_> {
    using Type = T_[size0_][size1_];
};

template<typename T_,
        template<typename, std::size_t...> typename Storage_,
        typename... IndexSlots_>
struct Tensor {
    typename Storage_<T_, IndexSlots_::size...>::Type _storage;
    Tensor() { std::cout << "Order N picked" << std::endl; }
};
template<typename T_,
        template<typename, std::size_t> typename Storage_,
        typename IndexSlot0_>
struct Tensor<T_, Storage_, IndexSlot0_> {
    typename Storage_<T_, IndexSlot0_::size>::Type _storage;
    Tensor() { std::cout << "Order 1 picked" << std::endl; }
};
template<typename T_,
        template<typename, std::size_t, std::size_t> typename Storage_,
        typename IndexSlot0_, typename IndexSlot1_>
struct Tensor<T_, Storage_, IndexSlot0_, IndexSlot1_> {
    typename Storage_<T_, IndexSlot0_::size, IndexSlot1_::size>::Type _storage;
    Tensor() { std::cout << "Order 2 picked" << std::endl; }
};

int main(int argc, char** argv) {
    Tensor<int, CArrayStorage, IndexSlot3> t1;
    Tensor<int, CArrayStorage, IndexSlot3, IndexSlot3> t2;
    Tensor<int, CArrayStorage, IndexSlot3, IndexSlot3, IndexSlot3> t3;

    return 0;
}

Вывод с Clang:

Order N picked
Order N picked
Order N picked

Выход с GCC:

Order 1 picked
Order 2 picked
Order N picked

Я думаю, что GCC прав, потому что специализация и основной матч одинаково хорошо, поэтому специализация должна быть выбрана. Но я не совсем уверен, как введение параметра шаблона шаблона меняет положение вещей.

Должен ли я сообщить об ошибке в Clang? Против GCC? Против обоих? Я забрел в область неопределенного поведения, не осознавая этого?

Любая помощь будет принята с благодарностью.

[Примеры не совсем минимальны, но я хотел предоставить немного контекста, чтобы вы могли понять, что я пытаюсь сделать.]

0 ответов

Другие вопросы по тегам