未命名的非类型模板参数有什么意义?
What's the point of unnamed non-type template parameters?
根据参考,非类型模板参数的名称是可选的,即使在分配默认值时也是如此(参见(1(和(2((。因此,这些模板结构是有效的:
template <int> struct Foo {};
template <unsigned long = 42> struct Bar {};
我还没有看到访问非类型参数值的可能性。 我的问题是:未命名/匿名非类型模板参数有什么意义?为什么名称是可选的?
首先,我们可以将声明与定义分开。 所以声明中的名字并没有真正的帮助。和名称可以在定义中使用
template <int> struct Foo;
template <unsigned long = 42> struct Bar;
template <int N> struct Foo {/*..*/};
template <unsigned long N> struct Bar {/*..*/};
专业化是定义的特例。
然后名称可以不使用,所以我们可能会省略它:
template <std::size_t, typename T>
using always_t = T;
template <std::size_t ... Is, typename T>
struct MyArray<std::index_sequence<Is...>, T>
{
MyArray(always_t<Is, const T&>... v) : /*..*/
};
或用于 SFINAE
template <typename T, std::size_t = T::size()>
struct some_sized_type;
未命名/匿名非类型模板参数的意义何在?
我能想到专业化:
template<int = 42>
struct Foo{
char x;
};
template<>
struct Foo<0> {
int x;
};
template<>
struct Foo<1> {
long x;
};
然后:
Foo<0> a; // x data member is int
Foo<1> b; // x data member is long
Foo<7> c; // x data member is char
Foo<> d; // x data member is char
哦,你可以访问它们!
template <int> struct Foo {};
template <int N>
int get(Foo<N>) {
return N;
}
int main() {
Foo<3> foo;
return get(foo);
}
这可能有点做作。但一般来说,对于某些模板,您不想命名它们,然后您不必命名很方便。
Unamed 类型和非类型参数还允许您使用模板模板参数延迟类型实例化。
以下面的函数为例destination_type
.
它可以解析为具有模板类型参数和 0 到 N 模板值参数的任何类型。
template <template <typename, auto...> typename destination_type, typename TupleType>
constexpr auto repack(TupleType && tuple_value)
{
return [&tuple_value]<std::size_t ... indexes>(std::index_sequence<indexes...>) {
return destination_type{std::get<indexes>(tuple_value)...};
}(std::make_index_sequence<std::tuple_size_v<TupleType>>{});
}
static_assert(repack<std::array>(std::tuple{1,2,3}) == std::array{1,2,3});
当您需要对参数包进行抽象时,这种机制会派上用场。
例如,在这里,我们不关心Ts...
是包含多个参数的参数包,还是扩展到本身具有多个模板参数的单个类型。
-> 可以从模板类型参数转换为模板值参数。
请参阅 gcl::mp::type_traits::p ack_arguments_as_t
完整的示例可在 godbolt 上找到 这里.
template <template <typename ...> class T, typename ... Ts>
class pack_arguments_as {
template <template <typename...> class PackType, typename... PackArgs>
constexpr static auto impl(PackType<PackArgs...>)
{
return T<PackArgs...>{};
}
template <typename... PackArgs>
constexpr static auto impl(PackArgs...)
{
return T<PackArgs...>{};
}
public:
using type = decltype(impl(std::declval<Ts>()...));
};
template <template <typename ...> class T, typename ... Ts>
using pack_arguments_as_t = typename pack_arguments_as<T, Ts...>::type;
namespace tests
{
template <typename... Ts>
struct pack_type {};
using toto = pack_arguments_as_t<std::tuple, pack_type<int, double, float>>;
using titi = pack_arguments_as_t<std::tuple, int, double, float>;
static_assert(std::is_same_v<toto, titi>);
static_assert(std::is_same_v<toto, std::tuple<int, double, float>>);
static_assert(std::is_same_v<pack_type<int, double, float>, pack_arguments_as_t<pack_type, toto>>);
}
相关文章:
- 传递给std::function template的template参数究竟代表什么
- 什么..(省略号)作为函数原型中唯一的函数参数,C++?
- C++部分概念 id:显式模板规范顺序/第一个参数的特殊状态的原因是什么?
- 引用捕获和在 lambda 中通过引用发送参数有什么区别 (C++)
- C++有什么方法可以在既不调用函数模板也不提供其模板参数的情况下引用函数模板?
- 读取大文件(>2GB)(文本文件包含以太网数据)并通过不同参数随机访问数据的最佳方法是什么?
- 未命名的非类型模板参数有什么意义?
- 有什么方法可以将具有不同模板参数的模板类实例放入向量中?
- 什么是仅调用一次并调用参数的控制台应用
- 在模板参数中使用 {} 在 type_trait{} 中时,其作用是什么<T>?
- 在 C 和 C++ 中作为函数参数,int **a 和 int a[][] 之间有什么确切的区别
- 为什么或在什么情况下,你会将参数作为C++中的引用(或指针)传递给函数?
- 没有大小参数的CString::GetBuffer()做什么
- 可变参数模板和省略号有什么区别?
- 当通知迭代器参数初始化为空列表的开头时,list::insert 行为是什么?
- C++ [错误] 声明'char '隐藏参数。什么意思?
- 用相同的参数声明两个构造函数的最偶像化的方法是什么?
- 这个公式在"accumulate"时采用什么参数?
- C++ 在发送什么参数方面遇到问题
- FindConnectionPoint,传递什么参数