获取元组元素的偏移量

sba*_*bbi 7 c++ tuples constexpr c++11

我编写了以下代码来获取元组元素的偏移量

template<size_t Idx,class T>
 constexpr size_t tuple_element_offset() {
        return static_cast<size_t>(
                    reinterpret_cast<char*>(&std::get<Idx>(*reinterpret_cast<T*>(0))) - reinterpret_cast<char*>(0));
    }
Run Code Online (Sandbox Code Playgroud)

这实际上类似于offsetof宏的实现.它看起来很难看,但在gcc-4.6上编译并正常工作

typedef std::tuple<int,char,long> mytuple;

mytuple var = std::make_tuple(4,'c',1000);
char * ptr = reinterpret_cast<char*>(&var);
long * pt = reinterpret_cast<long*>(ptr+tuple_element_offset<2,mytuple>());

std::cout << *pt << std::endl;
Run Code Online (Sandbox Code Playgroud)

打印"1000".

我对constexpr了解不多,所以我的问题是:

  1. 它是合法的c ++吗?
  2. 更重要的是,为什么我被允许在constexpr函数中调用std :: get(非constexpr)?

据我所知,constexpr,编译器被迫在编译时评估表达式的结果,因此在实践中不会发生零去引用.

Jam*_*lis 5

它是合法的C++吗?

如果"合法"的意思是"格式良好",那么,是的.

如果"合法"你的意思是"有效并将适用于任何编译器和标准库实现,那么,不,因为std::tuple不是POD.

为什么我被允许在函数内调用std::get(哪个不是constexpr)constexpr

基本上,constexpr函数不一定只需要一个常量表达式.如果您尝试tuple_element_offset()在常量表达式中使用函数,则会出现编译错误.

这个想法是一个函数可能在某些情况下可用于常量表达式而在其他情况下不可用,因此没有限制constexpr函数必须始终可用于常量表达式(因为没有这样的限制,它是特殊constexpr函数也可能永远不会在常量表达式中使用,就像你的函数一样).

C++ 0x草案有一个很好的例子(从5.19/2开始):

constexpr const int* addr(const int& ir) { return &ir; } // OK

// OK: (const int*)&(const int&)x is an address contant expression
static const int x = 5;
constexpr const int* xp = addr(x); 

// Error, initializer for constexpr variable not a constant expression; 
// (const int*)&(const int&)5 is not a constant expression because it takes
// the address of a temporary
constexpr const int* tp = addr(5);
Run Code Online (Sandbox Code Playgroud)