constexpr-if-else主体可以在constexpr自动功能中返回不同的类型吗? [英] Can constexpr-if-else bodies return different types in constexpr auto function?

查看:81
本文介绍了constexpr-if-else主体可以在constexpr自动功能中返回不同的类型吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个函数,该函数根据枚举的运行时值将值的枚举映射到一组类型.我意识到您不能基于枚举的运行时值返回不同的类型,因为编译器不知道要分配多少堆栈空间.但是,我正在尝试使用新的if-constexpr功能将其编写为constexpr函数.

I'm trying to write a function that maps an enumeration of values to a set of types based on the runtime value of the enumeration. I realize that you cannot return different types based on the runtime value of an enumeration because the compiler wouldn't know how much stack space to allocate. However I'm trying to write this as a constexpr function, using the new if-constexpr functionality to implement this.

我从clang收到错误消息,抱怨我使用的是非法指定的模板参数.有人看到如何实现这一点吗?

I'm getting an error from clang complaining that I'm using an illegally specified template parameter. Does anyone see how to implement this?

edit:这是一个更易于理解的版本,更简洁地演示了我的问题: http://coliru.stacked-crooked.com/a/2b9fef340bd167a8

edit: Here is an easier to grok version demonstrating my problem more concisely: http://coliru.stacked-crooked.com/a/2b9fef340bd167a8

旧代码:

#include <cassert>
#include <tuple>
#include <type_traits>

namespace
{

enum class shape_type : std::size_t
{
  TRIANGLE = 0u,
  RECTANGLE,
  POLYGON,
  CUBE,
  INVALID_SHAPE_TYPE
};

template<std::size_t T>
struct shape {
};

using triangle = shape<static_cast<std::size_t>(shape_type::TRIANGLE)>;
using rectangle = shape<static_cast<std::size_t>(shape_type::RECTANGLE)>;
using polygon = shape<static_cast<std::size_t>(shape_type::POLYGON)>;
using cube = shape<static_cast<std::size_t>(shape_type::CUBE)>;

template<std::size_t A, std::size_t B>
static bool constexpr same() noexcept { return A == B; }

template<std::size_t ST>
static auto constexpr make_impl(draw_mode const dm)
{
  if constexpr (same<ST, shape_type::TRIANGLE>()) {
    return triangle{};
  } else if (same<ST, shape_type::RECTANGLE>()) {
    return rectangle{};
  } else if (same<ST, shape_type::POLYGON>()) {
    return polygon{};
  } else if (same<ST, shape_type::CUBE>()) {
    return cube{};
  } else {
    assert(0 == 5);
  }
}

static auto constexpr make(shape_type const st, draw_mode const dm)
{
  switch (st) {
      case shape_type::TRIANGLE:
        return make_impl<shape_type::TRIANGLE>(dm);
      case shape_type::RECTANGLE:
        return make_impl<shape_type::RECTANGLE>(dm);
      case shape_type::POLYGON:
        return make_impl<shape_type::POLYGON>(dm);
      case shape_type::CUBE:
        return make_impl<shape_type::CUBE>(dm);
      case shape_type::INVALID_SHAPE_TYPE:
        assert(0 == 17);
  }
}

} // ns anon

////////////////////////////////////////////////////////////////////////////////////////////////////
// demo
int main()
{
}

错误:

/home/benjamin/github/BoomHS/main.cxx:42:6: warning: constexpr if is a
C++1z extension [-Wc++1z-extensions]

if constexpr (same<ST, shape_type::TRIANGLE>()) {
        ^ /home/benjamin/github/BoomHS/main.cxx:59:16: error: no matching function for call to 'make_impl'
        return make_impl<shape_type::TRIANGLE>(dm);
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/benjamin/github/BoomHS/main.cxx:40:23: note: candidate template
ignored: invalid explicitly-specified argument for template parameter
'ST' static auto constexpr make_impl(draw_mode const dm)
                      ^ /home/benjamin/github/BoomHS/main.cxx:61:16: error: no matching function for call to 'make_impl'
        return make_impl<shape_type::RECTANGLE>(dm);
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/benjamin/github/BoomHS/main.cxx:40:23: note: candidate template
ignored: invalid explicitly-specified argument for template parameter
'ST' static auto constexpr make_impl(draw_mode const dm)
                      ^ /home/benjamin/github/BoomHS/main.cxx:63:16: error: no matching function for call to 'make_impl'
        return make_impl<shape_type::POLYGON>(dm);
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/benjamin/github/BoomHS/main.cxx:40:23: note: candidate template
ignored: invalid explicitly-specified argument for template parameter
'ST' static auto constexpr make_impl(draw_mode const dm)
                      ^ /home/benjamin/github/BoomHS/main.cxx:65:16: error: no matching function for call to 'make_impl'
        return make_impl<shape_type::CUBE>(dm);
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/benjamin/github/BoomHS/main.cxx:40:23: note: candidate template
ignored: invalid explicitly-specified argument for template parameter
'ST' static auto constexpr make_impl(draw_mode const dm)

推荐答案

是的,允许您尝试执行任何操作.我在 N4606 是:

Yes, what you are attempting is allowed. The two relevant excerpts I've found in N4606 are:

6.4.1/2 [stmt.if]

6.4.1/2 [stmt.if]

如果if语句的形式为if constexpr [...] 转换后的条件为假,则第一个子语句为废弃的语句,否则,第二个子语句(如果存在)为废弃的语句.

If the if statement is of the form if constexpr [...] If the value of the converted condition is false, the first substatement is a discarded statement, otherwise the second substatement, if present, is a discarded statement.

表示 constexpr中的未使用分支(如果是已废弃的语句).此外,自动函数仅考虑未丢弃的return语句来推断返回类型

Indicating an untaken branch in a constexpr if is a discarded statment. Further, auto functions only consider non-discarded return statements for deducing the return type

7.1.7.4/2 [dcl.spec.auto](强调我的意思)

7.1.7.4/2 [dcl.spec.auto] (emphasis mine)

[...]如果函数的声明返回类型包含占位符类型,则该函数的返回类型由未丢弃的返回语句推导(如果有的话),位于功能(6.4.1).

[...] If the declared return type of the function contains a placeholder type, the return type of the function is deduced from non-discarded return statements, if any, in the body of the function (6.4.1).

经过简化,以下代码可同时在 gcc

Simplified, the following code works on both gcc and clang head.

namespace {

enum class shape_type { TRIANGLE, RECTANGLE, CIRCLE};

template<shape_type>
struct shape { };

using triangle = shape<shape_type::TRIANGLE>;
using rectangle = shape<shape_type::RECTANGLE>;
using circle = shape<shape_type::CIRCLE>;

template<shape_type ST>
constexpr auto make() {
  if constexpr (ST == shape_type::TRIANGLE) {
    return triangle{};
  } else if constexpr (ST == shape_type::RECTANGLE) {
    return rectangle{};
  } else if constexpr (ST == shape_type::CIRCLE) {
    return circle{};
  } 
}

}

int main() {
  auto t = make<shape_type::TRIANGLE>();
  auto r = make<shape_type::RECTANGLE>();
  auto c = make<shape_type::CIRCLE>();
}

这篇关于constexpr-if-else主体可以在constexpr自动功能中返回不同的类型吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆