下面的玩具示例演示了我想要实现的目标。
#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"
有没有办法让我有两个这样的模板专门化 - 一个使用显式字节大小(非类型参数),另一个使用sizeof()
类型的大小(T
} (类型参数)?我对一个不需要两个具有不同名称或任何#define
宏的独立模板的解决方案感兴趣。
我试图在&#34;反向&#34; - 将<typename T>
作为主要模板,使用size_t
作为专业化(将char[sizeof(T)]
或std::aligned_storage<...>::type
传递给主模板),但也失败了。
答案 0 :(得分:3)
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:
专业化应比主要模板
更专业化
绝不是size_t
比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)> { };
答案 1 :(得分:2)
类模板不能重载。如果类模板Buffer
采用类型为size_t
的非类型参数,那么每次编写Buffer<thing>
时,thing
必须是有效的非类型参数;它不是一种类型。相反的情况也是如此 - 如果Buffer
采用类型参数,则每次撰写Buffer<thing>
thing
时都必须成为类型。
部分特化的模板参数在部分特化匹配期间始终推导;你永远不能明确指定它们。
但是,功能模板可能会重载。因此,您可以编写重载make_buffer
并使用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;
然后,您可以轻松地为此编写宏。