【问题标题】:Cannot convert from initializer_list to my type, which has templated variadic constructor无法从 initializer_list 转换为我的类型,该类型具有模板化的可变参数构造函数
【发布时间】:2021-08-28 02:11:55
【问题描述】:

所以,这不是我真正必须做的事情,我只是在玩。我为任何数字类型和任意数量坐标的向量编写了一个Vector 类。它用作Vector<NumericType, [num of coords]>。代码如下:

#include <array>
#include <functional>

namespace World {

template <typename NumType, unsigned char Size>
class Vector
{
public:
  using CoordType = NumType;


  template<typename... NumTypes>
  constexpr Vector(NumTypes&&... vals) : values{ std::forward<NumTypes>(vals)... }
  {
    static_assert(sizeof...(NumTypes) == Size, "You must provide N arguments.");
  }

  Vector(const std::array<NumType, Size>& values) : values(values) {}
  Vector(const std::array<NumType, Size>&& values) : values(std::move(values)) {}

  const NumType& operator[](size_t offset) const { return values[offset]; }
  NumType& operator[](size_t offset) { return values[offset]; }

  //! Converts all values to new given type
  template <typename NewType>
  constexpr Vector<NewType, Size> Convert() const { return Convert<NewType>(std::make_index_sequence<Size>{}); }
  //! Converts all values via the conversion function
  template <typename NewType>
  Vector<NewType, Size> Convert(const std::function<NewType(NumType)>& callback) const { return Convert<NewType>(std::make_index_sequence<Size>{}, callback); }

  std::array<NumType, Size> values;

private:
  //! Converts all values to new given type
  template <typename NewType, std::size_t ... Is>
  constexpr Vector<NewType, Size> Convert(std::index_sequence<Is...>) const { return { { static_cast<NewType>(values[Is])}... }; }
  //! Converts all values via the conversion function
  template <typename NewType, std::size_t ... Is>
  Vector<NewType, Size> Convert(std::index_sequence<Is...>, const std::function<NewType(NumType)>& callback) const { return { { callback(values[Is])}... } ; }
};

现在我要做的是确保上面声明的转换函数正常工作。使用思路是这样的:

using namespace World;
using Vector3D = Vector<double, 3>;
using Vector3Int = Vector<int, 3>;

#include <cmath>

int main()
{
  const Vector3D src{ 1.4, 2.5, 3.6 };
  const Vector3Int target = src.Convert<int>([](double val) { return (int)std::round(val); });
  return 0;
}

这里的问题是编译转换函数时,生成的新值以std::initializer_list&lt;NewType&gt;的形式出现。由于某种原因,这不符合构造函数Vector(NumTypes&amp;&amp;... vals) 的条件。现在我不想有一个初始化列表构造函数 - 预期参数的数量不是可变的,它必须是 Size 模板参数所说的任何内容。

那么如何解决这个问题?如何将 std::initializer_list 转换为 NumTypes&amp;&amp;... vals 是什么?

我必须在这里承认,我并不确切地知道我在做什么,我正在努力提高我的 C++ 知识。

【问题讨论】:

  • 我没有仔细看,但是Convert 函数是否应该像这样返回:return { {callback(values[Is])... } } ;
  • OT:首先,常量右值引用没有意义(特别是,如果您稍后试图从它们“移动”)。其次,基本类型的完美转发也没有意义。对于 intdouble 这样的类型,复制和移动之间没有区别。
  • @TedLyngmo 成功了,你真是个天才!但是点的位置是基于其他代码,当它们位于括号后面时,它们会起作用......你能否发布一个答案来解释 {{x...}}{{x}...} 之间的区别?
  • @TomášZato-ReinstateMonica Cool(简体:return {callback(values[Is])...}; 也应该可以)。我写不出答案。 3小时的会议现在开始。我会把它留给别人。 :-)
  • @TomášZato-ReinstateMonica 我看到没有人拿起球,所以我试图通过使用示例来解释它。我觉得我自己解释得不好,所以我希望其他人能做出更好的答案(或者如果可以挽救的话,可以改进我的答案)

标签: c++ templates c++17 variadic-templates initializer-list


【解决方案1】:

Convert 中,您有参数包Is,您希望将其与callbackvalues 结合使用。

参数包扩展“扩展为以逗号分隔的零个或多个模式列表”,因此当与问题中的值一起使用时,您会得到以下结果:

Is...

0, 1, 2

values[Is]... => values[0], values[1], values[2]

1.4, 2.5, 3.6

callback(values[Is])... => callback(values[0]), callback(values[1]), callback(values[2])

1, 3, 4

你想像这样创建一个 braced-init-list

{callback(values[0]), callback(values[1]), callback(values[2])}
// =>
{1, 3, 4}

所以:

template <typename NewType, std::size_t... Is>
Vector<NewType, Size> 
        Convert(std::index_sequence<Is...>, 
                const std::function<NewType(NumType)>& callback) const
{
    return {callback(values[Is])...};
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多