首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Constexpr成员函数

Constexpr成员函数
EN

Stack Overflow用户
提问于 2019-11-14 21:15:29
回答 3查看 2.8K关注 0票数 5

假设我有一个由引擎参数化的struct模板S

代码语言:javascript
复制
template<class Engine> struct S;

我有两个引擎:一个带有constexpr成员函数size()的“静态”引擎,和一个非constexpr成员函数size()的“动态”引擎。

代码语言:javascript
复制
struct Static_engine {
    static constexpr std::size_t size() {
        return 11;
    }
};

struct Dynamic_engine {
    std::size_t size() const {
        return size_;
    }
    std::size_t size_ = 22;
};

我想在size()中定义S成员函数,如果引擎的size()constexpr,它可以作为constexpr使用。我写道:

代码语言:javascript
复制
template<class Engine>
struct S {
    constexpr std::size_t size() const {
        return engine_.size();
    }
    Engine engine_;
};

然后用GCC、Clang、MSVC和ICC编译以下代码:

代码语言:javascript
复制
S<Static_engine> sta;         // not constexpr
S<Dynamic_engine> dyn;

constexpr auto size_sta = sta.size();
const auto size_dyn = dyn.size();

考虑到constexpr的复杂性和各种“格式错误,不需要诊断”,我仍然有一个问题:这段代码是否格式良好?

Godbolt.org上的完整代码

(如果这段代码在这两种标准中具有不同的有效性,我会用c++17c++20标记这个问题。)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-11-14 21:20:55

代码写得很好。

dcl.constexpr 6如果类模板的constexpr函数模板或成员函数的实例化模板专门化将无法满足对constexpr函数或constexpr构造函数的要求,则即使对此类函数的调用不能出现在常量表达式中,该专门化仍然是constexpr函数或constexpr构造函数。如果当模板被视为非模板函数或构造函数时,模板的任何专门化都不能满足对constexpr函数或constexpr构造函数的要求,则模板的格式不正确,不需要诊断。

对于使用Dynamic_engine的专门化,成员可能不会出现在常量表达式中,但正如上面的段落所详细说明的那样,这不会使S::size格式不正确。我们也远离不正确的NDR领土,因为有效的实例化是可能的.Static_engine就是一个很好的例子。

引用来自n4659,最后一个C++17标准草案,类似的措辞出现在最新的C++20草案中。

至于将sta.size()作为常量表达式的计算,在[expr.const]上查看列表时,我无法在计算本身中找到不允许的任何内容。因此,它是一个有效的常量表达式(因为列表告诉我们什么是无效的)。通常,要使constexpr函数有效,只需要存在一些参数,计算值就会产生一个有效的常量表达式。如以下示例所示,该标准说明:

代码语言:javascript
复制
constexpr int f(bool b)
  { return b ? throw 0 : 0; }           // OK
constexpr int f() { return f(true); }   // ill-formed, no diagnostic required

struct B {
  constexpr B(int x) : i(0) { }         // x is unused
  int i;
};

int global;

struct D : B {
  constexpr D() : B(global) { }         // ill-formed, no diagnostic required
                                        // lvalue-to-rvalue conversion on non-constant global
};
票数 7
EN

Stack Overflow用户

发布于 2019-11-14 21:23:49

是。

函数可以标记为constexpr,而无需在编译时进行计算。只要您满足将函数标记为constexpr的其他要求,就可以了(返回文字类型,参数是文字,没有内联的asm,等等)。唯一可能遇到问题的情况是,如果实际上不可能创建满足作为核心常量表达式调用的函数的参数。(例如,如果您的函数对所有值都有未定义的行为,那么您的函数将是格式错误的NDR)

在C++20中,我们接收到consteval说明符,该说明符强制所有对函数的调用都能够生成编译时常量(constexpr)。

票数 2
EN

Stack Overflow用户

发布于 2019-11-14 22:05:25

不是直接回答而是另一种方式:

代码语言:javascript
复制
struct Dynamic_Engine
{
  using size_type = size_t;

  size_type size() const
  {
    return _size;
  }

  size_type _size = 22;
};
struct Static_Engine
{
  using size_type = std::integral_constant<size_t, 11>;

  size_type size() const
  {
    return size_type();
  }
};

template <typename ENGINE>
struct S
{
  auto size() const
  {
    return _engine.size();
  }

  ENGINE _engine;
};

int main()
{
  S<Static_Engine>  sta;
  S<Dynamic_Engine> dyn;

  const auto size_sta = sta.size();
  const auto size_dyn = dyn.size();

  static_assert(size_sta == 11);
}

我遇到了同样的问题,IMHO --最简单、更通用的解决方案是使用std::integral_constant。不需要更多地与constexpr混搭,因为大小信息直接编码到类型中。

如果您仍然想使用constexpr (及其额外的复杂性),您可以这样做:

代码语言:javascript
复制
struct Dynamic_Engine
{
  size_t size() const
  {
    return _size;
  }

  size_t _size = 22;
};
struct Static_Engine
{
  static constexpr size_t size() // note: static 
  {
    return 11;
  }
};

template <typename ENGINE>
struct S
{
  constexpr size_t size() const
  {
    return _engine.size();
  }

  ENGINE _engine;
};

int main()
{
  S<Static_Engine>  sta;
  S<Dynamic_Engine> dyn;

  constexpr size_t size_sta = sta.size();
  const size_t size_dyn = dyn.size();

  static_assert(size_sta == 11);
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58866631

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档