获取元组元素的偏移量

发布于 2024-10-23 14:12:55 字数 918 浏览 3 评论 0原文

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

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));
    }

这实际上类似于 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;

打印“1000”。

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

  1. 它是合法的 c++ 吗?
  2. 更重要的是,为什么我可以打电话 std::get (非 constexpr) 在 constexpr 函数内?

据我了解 constexpr,编译器被迫评估结果 在编译时对表达式进行修改,因此在实践中不会发生零引用。

I have wrote the following code to get the offset of a tuple element

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));
    }

This is actually similar to the implementation of the offsetof macro.
It looks ugly, but compiles and works fine on 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;

prints "1000".

I don't know too much about constexpr, so my questions are:

  1. Is it legal c++?
  2. More important, why I am allowed to call
    std::get (which is non constexpr)
    inside a constexpr function?

As far as I understand constexpr, the compiler is forced to evaluate the result
of the expression at compile time, so no zero-dereferentiation can occurs in practice.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

浅浅 2024-10-30 14:12:55

它是合法的 C++ 吗?

如果“合法”是指“格式良好”,那么,是的。

如果“合法”的意思是“有效并且可以在任何编译器和标准库实现上工作,那么不行,因为 std::tuple 不是 POD。

为什么我可以在 constexpr 函数内调用 std::get (不是 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);

Is it legal C++?

If by "legal" you mean "well-formed," then, yes.

If by "legal" you mean "valid and will work on any compiler and Standard Library implementation, then, no, because std::tuple is not POD.

Why I am allowed to call std::get (which is not constexpr) inside a constexpr function?

Basically, a constexpr function doesn't necessarily have to consist of just a constant expression. If you tried to use your tuple_element_offset() function in a constant expression, you'd get a compilation error.

The idea is that a function might be usable in a constant expression in some circumstances but not in others, so there isn't a restriction that a constexpr function must always be usable in a constant expression (since there isn't such a restriction, it's also possible that a particular constexpr function might never be usable in a constant expression, as is the case with your function).

The C++0x draft has a good example (from 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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文