考虑这个(最小化)示例:
template <typename Descriptor>
class hash_table
{
public:
typedef int value_type;
template <typename Argument, int Callback (value_type *, Argument)>
void traverse (Argument);
template <int Callback (value_type *)>
void traverse_void ();
};
Run Code Online (Sandbox Code Playgroud)
我定义了一个类模板,它具有带非类型参数的模板成员函数.请注意,这Callback取决于value_typetypedef.现在我想定义函数本身:
template <typename Descriptor>
template <typename Argument, int Callback (typename hash_table <Descriptor>::value_type *, Argument)>
void hash_table <Descriptor>::traverse (Argument) {}
template <typename Descriptor>
template <int Callback (typename hash_table <Descriptor>::value_type *)>
void hash_table <Descriptor>::traverse_void () {}
Run Code Online (Sandbox Code Playgroud)
我从编译器中得到了不一致的错误.结果不依赖于选项,指定C++标准的版本(即C++ 98,C++ 11和C++ 14的版本),但取决于编译器.
GCC 6.0.0(最近的主干,以及其他几个版本)接受此代码.
Clang 3.7.0(最近的trunk)给出以下错误:
test.cc:18:31: error: out-of-line …Run Code Online (Sandbox Code Playgroud) 前言.我试图对C++模板元编程有一些更深入的了解,似乎我被卡住了...我正在编写一个库,我们将用它来进行二进制数据[de]序列化.正在解压缩的数据的预期结构在某种程度上是已知的,并且使用这些知识(1)验证数据(2)跳过不相关的部分以及(3)将数据直接解压缩到编译时已知的结构中似乎是合理的. - 用于避免不必要的复制并使客户端代码看起来更清晰.
因此,例如,我想实现一个解包数组的函数(数组可以包含异构数据,如JSON).为简单起见,假设数组具有固定大小,并且没有嵌套.
实际问题我想写一个函数,它将包含一个包含序列化数据的输入缓冲区(或一个流 - 在我们的上下文中无关紧要)和一个std::tuple包含输出的左值(参数包是一个更糟糕的选择,因为我最终必须处理嵌套问题.因此,我首先需要检查一个元组中的所有类型是否适合解包器,并提供相关的错误消息,如果不是.
所以代码是这样的:
template<typename T>
struct is_integral_lvalue : std::integral_constant<bool,
std::is_lvalue_reference<T>::value &&
std::is_integral<T>::value &&
(sizeof(T) == 4 || sizeof(T) == 8)>
{
};
/* ... */
template<typename TInputBuffer, typename... TDest>
static TRet unpack_int_tuple(TInputBuffer src_buf, std::tuple<TDest...> &&dest) noexcept(is_noexcept)
{
static_assert(typelist::all_are<is_integral_lvalue, TDest...>::value,
"All types in a tuple must be integral lvalue-references");
/* do unpacking */
}
Run Code Online (Sandbox Code Playgroud)
这种情况is_integral_constant可能有些武断.这就是为什么all_are模板可以使用任何一元谓词的原因.问题是:我应该写什么typelist::all_are(也许,我应该在上面的代码中解决什么才能编写这样的代码all_are)?
一个工作的例子当然是理想的,但如果它们有用,我会很感激一般的想法/建议.
限制我的目标不仅仅是实现这个功能,而是要了解它是如何工作的(像"使用boost :: mpl"或"boost :: hana"这样的解决方案是不合适的).我们使用的不太相关的东西越多越好.最好是代码应该是C++ 11(我们还没准备好在生产中使用C++ 1y/GCC …
我曾经以为,支持x86-64的未对齐的内存访问和无效的内存访问总是引起分段错误(除非,也许,SIMD指令像movdqa或movaps).不过最近我用正常mov指令观察到了总线错误.这是一个复制者:
void test(void *a)
{
asm("mov %0, %%rbp\n\t"
"mov 0(%%rbp), %%rdx\n\t"
: : "r"(a) : "rbp", "rdx");
}
int main()
{
test((void *)0x706a2e3630332d69);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
(必须用帧指针省略编译,例如gcc -O test.c && ./a.out).
mov 0(%rbp), %rdx指令和地址0x706a2e3630332d69是从有缺陷的程序的coredump复制的.将其更改为0会导致段0x706a2e3630332d60错误,但只是对齐仍然是总线错误(我的猜测是它与地址空间在x86-64上的48位相关).
问题是:哪些地址导致总线错误(SIGBUS)?它是由体系结构决定还是由OS内核配置(即在页表,控制寄存器或类似的东西中)?