我对模板专业化以及可变参数模板和模板模板参数/参数有疑问。
以下小程序使用 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? 反对两者? 我是否已经进入未定义行为的境界而没有意识到呢?
任何帮助将不胜感激。
[示例并非完全是最小的,但我想提供一些上下文,以便您可以理解我的工作。]