将“类型参数”与“非类型参数”(或相反)专门化
Specializing "type argument" with "non-type argument" (or the other way around)
我想实现的目标通过下面的玩具示例进行了演示。
#include <cstddef>
template<size_t ElementSize>
class Buffer
{
public:
char buffer[ElementSize];
};
template<typename T>
class Buffer<sizeof(T)>
{
public:
char buffer[sizeof(T)];
};
int main()
{
Buffer<4> b1; // buffer with 4 bytes
Buffer<int> b2; // buffer with space for "int"
}
这段代码显然无法编译:
$ g++ test.cpp
test.cpp:12:7: error: template argument ‘sizeof (T)’ involves template parameter(s)
class Buffer<sizeof(T)>
^
test.cpp: In function ‘int main()’:
test.cpp:22:12: error: type/value mismatch at argument 1 in template parameter list for ‘template<long unsigned int ElementSize> class Buffer’
Buffer<int> b2; // buffer with space for "int"
^
test.cpp:22:12: error: expected a constant of type ‘long unsigned int’, got ‘int’
test.cpp:22:16: error: invalid type in declaration before ‘;’ token
Buffer<int> b2; // buffer with space for "int"
有什么方法可以让我拥有这种模板的两个专用化 - 一个使用以字节为单位的显式大小(非类型参数),另一个从类型T
(类型参数)中获取大小(带sizeof()
)?我对不需要两个具有不同名称或任何#define
宏的单独模板的解决方案感兴趣。
我试图以"反向"方式实现它 - 将 <typename T>
作为主模板,并使用size_t
作为专用化模板(将char[sizeof(T)]
或std::aligned_storage<...>::type
传递给主模板),但这也失败了。
不,你不能。一旦我们有了template <size_t Size> class Buffer
,我们就非常有限地限制了我们能做的专业化。即 §14.5.5/8.1:
部分专用的非类型参数表达式不得涉及 部分专用化,除非参数表达式是简单标识符。[示例:
template <int I, int J> struct A {}; template <int I> struct A<I+5, I*2> {}; // error template <int I, int J> struct B {}; template <int I> struct B<I, I> {}; // OK
- 结束示例 ]
因此,我们唯一能做的部分专业化是:
template <size_t I> class Buffer<I> { .. };
违反§14.5.5/8.3
专业化的参数列表不应与主模板的隐式参数列表相同。
在另一个方向,我们违反了 14.5.5/8.4:
专业化绝不应比主模板更专业化
是比T
更专业的size_t
.
您可以做的只是创建一个别名:
template <size_t ElementSize>
class Buffer {
char buffer[ElementSize];
};
template <typename T>
using BufferFromType = Buffer<sizeof(T)>;
// or, if not C++11, another type
template <typename T>
class BufferFromType : public Buffer<sizeof(T)> { };
类模板不能重载。如果类模板Buffer
采用类型 size_t
的非类型参数,则每次编写Buffer<thing>
时,thing
都必须是有效的非类型参数;它不能是一种类型。反之亦然 - 如果Buffer
采用类型参数,那么每次编写Buffer<thing>
thing
时都必须是一个类型。
化的模板参数始终在部分专用化匹配期间推导;您永远不能显式指定它们。
但是,函数模板可能会重载。所以你可以写重载make_buffer
s并使用auto
:
template<class T> Buffer<sizeof(T)> make_buffer() { return {}; }
template<size_t Size> Buffer<Size> make_buffer() { return {}; }
auto buffer1 = make_buffer<int>();
auto buffer2 = make_buffer<42>();
你可以使用decltype
来实现统一但折磨人的语法:
decltype(make_buffer<int>()) buffer1;
decltype(make_buffer<42>()) buffer2;
然后,您可以为此轻松编写宏。
- 在 c++ 中的模板实例化中使用带有构造函数的类作为类型参数
- 如何解决一元"*"(有"字符")错误的无效类型参数?
- "std::shared_ptr":不是参数"_Ty"的有效模板类型参数
- 具有可变参数非类型参数的模板专用化
- 函数类型参数的模板参数推导
- PowerShell 使用结构类型参数调用 C++ DLL 的导出函数
- 对于非常量指针类型的参数,未调用具有常量指针模板类型参数的功能
- 为模板传递非类型参数 agument
- 为什么带有类型参数的运算符 () 可以应用于 result_of 上下文中的类型?
- 使用其他模板类型参数作为要在函数签名中使用的类型别名声明
- 如何避免具有相同类型参数的函数中的错误
- 将内置类型变量传递给只有一个类类型参数的"+"运算符函数时自动类型转换的构造函数
- c++非类型参数包扩展
- 如何实现对参数顺序不可知的std::same_as的广义形式(即对于两个以上的类型参数)
- 在不同的模板参数包之间分发非类型参数包
- g++和clang++在结构/类专门化中具有非类型参数的不同行为
- 将“类型参数”与“非类型参数”(或相反)专门化
- 如何测试类型是否是带有非类型参数的模板的专门化
- 是否可以基于模板类型参数的嵌套类型定义来专门化模板定义
- 带非类型参数的成员函数的部分专门化