【问题标题】:No matching constructor for initialization of variadic template class无匹配构造函数用于初始化Variadic模板类
【发布时间】:2019-09-29 05:35:32
【问题描述】:

我正在尝试为 Miranda Conrado 提供的笛卡尔积迭代器编写一个包装类(源代码可在 GitHub 上找到)。为方便起见,我也会在这里引用相关的代码。

我的类可以通过两种方式构建——一种直接,将容器转发到product_iterator 构造函数,另一种有点棘手:它需要一些元组来描述创建容器所需的 linspace,然后用它们构造迭代器。在这里我遇到了死胡同。

这是一些代码。 首先,来自Conrado的class product_iterator的一些相关标头:

// product_iterator.hpp

template <class... Containers>
class product_iterator:
    ...

    public:
      product_iterator();

      product_iterator(product_iterator const& other);

      product_iterator(Containers const&... containers);

      ~product_iterator();

      product_iterator const& operator=(product_iterator const& other);

     ....
};

template <class... Containers>
product_iterator<Containers...>
make_product_iterator(Containers const&... containers) {
  return product_iterator<Containers...>(containers...);
}

这是我的课:

// gridsearch.hpp

typedef std::unordered_map<std::string, Real> result_type;
typedef std::vector<result_type> resultgrid_type;


template <class... Containers>
class GridSearchIterator {
    typedef std::array<std::string,
            std::tuple_size<std::tuple<Containers...> >::value> 
            argname_type;

public:
    GridSearchIterator() : product_it(product_iterator<Containers...>()), 
                           argnames(argname_type()) {}

    GridSearchIterator(const argname_type& names, 
                       const Containers& ...containers);

    template <class... TupleTypes>
    static GridSearchIterator<Containers...> 
                                    initWith(const TupleTypes&& ...tuples);

    template<class F, class... Args>
    decltype(auto) iterate(F func, Args&&... params);

private:
    template <typename TupleType, size_t... Is>
    void product_impl(TupleType&& tuples, std::index_sequence<Is...>);
    template <typename TupleType>
    const auto& unpack_tuple(TupleType& t, size_t index);

    product_iterator<Containers...> product_it;
    argname_type argnames;
};

// implementation:

template <class... Containers>
GridSearchIterator<Containers...>::GridSearchIterator(
                                          const argname_type& names, 
                                          const Containers& ...containers):

                product_it(product_iterator<Containers...>(containers...)),
                                                        argnames(names) {}

template <class... Containers>
template <typename... TupleTypes>
GridSearchIterator<Containers...> GridSearchIterator<Containers...>::initWith(const TupleTypes&& ...tuples) 
{
    GridSearchIterator<Containers...> gsi = 
                                       GridSearchIterator<Containers...>();
    gsi.product_impl(std::tuple<TupleTypes...>(tuples...), 
                     std::index_sequence_for<TupleTypes...>{});
    return gsi;
}

template <class... Containers>
template <typename TupleType, size_t... Is>
void GridSearchIterator<Containers...>::product_impl(TupleType&& tuples, 
                                              std::index_sequence<Is...>) 
{
    product_it = product_iterator<Containers...>(
                                unpack_tuple(std::get<Is>(tuples), Is)...); 
// this is where the problem is; Compiler claims No matching constructor for initialization of 'product_iterator...
}

template <class... Containers>
template <typename TupleType>
const auto& GridSearchIterator<Containers...>::unpack_tuple(TupleType &t, 
                                                            size_t index) 
{
    std::string argname;
    auto left(0), right(0);
    Size step;
    std::tie(argname, left, right, step) = t;
    argnames[index] = argname;
    auto vec = linspace(left, right, step);
    return static_cast<const decltype(vec) &>(vec);
}

上面的函数linspace 返回一个从left 到right 的数字向量,它们之间的间距是steps 的个数。相当于Numpy函数np.linspace。

我检查了对unpack_tuple() 的调用确实产生了初始化product_iterator 所需的向量,但编译器不同意。我的猜测是 unpack_tuple() 返回的类型与 product_iterator 构造函数所期望的有些不同,但我无法弄清楚问题出在哪里。或者,问题实际上完全出在其他地方。

为了更好地理解,我是这样使用这个类的:

{
...
    typedef std::tuple<std::string, int, int, size_t> inttuple;
    typedef std::tuple<std::string, double, double, size_t> realtuple;
    typedef std::vector<int> intvector;
    typedef std::vector<Real> realvector;

    inttuple sidespan = std::make_tuple("side",1,1,1);
    real tuple takeprofit = std::make_tuple("takeprofit",1.,2.,2);
    real tuple stoploss = std::make_tuple("stoploss", -1.,-3.,3);
    inttuple period = std::make_tuple("horizon", 100, 100, 1);

    auto grid_iter = GridSearchIterator<intvector, realvector, realvector, intvector>
                                        ::initWith(std::forward<inttuple>(sidespan),
                                                   std::forward<realtuple>(takeprofit),
                                                   std::forward<realtuple>(stoploss),
                                                   std::forward<inttuple>(period));
...
}

我花了几个小时试图解决它,因此任何帮助或指示都将受到高度赞赏,包括有关不同实现的建议。

更新
抱歉,我以为我昨天更新了我的问题,但由于某种原因没有保存更改。 无论如何,@max66 即使没有其他信息也回答了这个问题。不过,为了完整起见,这里是linspace() 定义

template <typename T>
std::vector<T> linspace(T a, T b, size_t N)

和编译器消息:

在 /.../main.cpp:17 中包含的文件中:
/.../gridsearch.hpp:98:18: 错误:'product_iterator<std::__1::vector<int, std::__1::allocator<int> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<int, std::__1::allocator<int> > >' product_it = product_iterator<Containers...>(unpack_tuple(std::get<Is>(tuples), Is)...); 的初始化没有匹配的构造函数

/.../gridsearch.hpp:91:9: 注意:在函数模板特化'GridSearchIterator&lt;std::__1::vector&lt;int, std::__1::allocator&lt;int&gt; &gt;, std::__1::vector&lt;double, std::__1::allocator&lt;double&gt; &gt;, std::__1::vector&lt;double, std::__1::allocator&lt;double&gt; &gt;, std::__1::vector&lt;int, std::__1::allocator&lt;int&gt; &gt; &gt;::product_impl&lt;std::__1::tuple&lt;std::__1::tuple&lt;std::__1::basic_string&lt;char&gt;, int, int, unsigned long&gt;, std::__1::tuple&lt;std::__1::basic_string&lt;char&gt;, double, double, unsigned long&gt;, std::__1::tuple&lt;std::__1::basic_string&lt;char&gt;, double, double, unsigned long&gt;, std::__1::tuple&lt;std::__1::basic_string&lt;char&gt;, int, int, unsigned long&gt; &gt;, 0, 1, 2, 3&gt;' 在这里请求gsi.product_impl(std::tuple&lt;TupleTypes...&gt;(tuples...), std::index_sequence_for&lt;TupleTypes...&gt;{}); 的实例化中

/.../main.cpp:90:88: 注意:在函数模板特化'GridSearchIterator&lt;std::__1::vector&lt;int, std::__1::allocator&lt;int&gt; &gt;, std::__1::vector&lt;double, std::__1::allocator&lt;double&gt; &gt;, std::__1::vector&lt;double, std::__1::allocator&lt;double&gt; &gt;, std::__1::vector&lt;int, std::__1::allocator&lt;int&gt; &gt; &gt;::initWith&lt;std::__1::tuple&lt;std::__1::basic_string&lt;char&gt;, int, int, unsigned long&gt;, std::__1::tuple&lt;std::__1::basic_string&lt;char&gt;, double, double, unsigned long&gt;, std::__1::tuple&lt;std::__1::basic_string&lt;char&gt;, double, double, unsigned long&gt;, std::__1::tuple&lt;std::__1::basic_string&lt;char&gt;, int, int, unsigned long&gt; &gt;'在此请求auto grid_iter = GridSearchIterator&lt;intvector, realvector, realvector, intvector&gt;::initWith(std::forward&lt;inttuple&gt;(sidespan),的实例化中

在 /.../main.cpp:17 中包含的文件中:
在 /.../gridsearch.hpp:22 包含的文件中: /.../product_iterator.hpp:73:7:注意:候选构造函数不可行:从 'vector&lt;int, allocator&lt;int&gt;&gt;' to 'const vector&lt;double, allocator&lt;double&gt;&gt;' 到第二个参数 product_iterator(Containers const&amp;... containers); 没有已知转换

【问题讨论】:

  • “但编译器不同意” - 这很模糊,并且包含了您的解释/假设。这使得该语句在很大程度上对调试帮助毫无用处。编译器的确切信息是什么?
  • 请提供linspace函数原型和完整的编译错误

标签: c++ c++11 variadic-templates template-meta-programming stdtuple


【解决方案1】:

如果您不提出完整的示例,就很难检查/验证/提出正确的代码。

无论如何你在这一行有错误(“没有匹配的构造函数”)

    product_it = product_iterator<Containers...>(
                                unpack_tuple(std::get<Is>(tuples), Is)...); 

如果我理解正确,Containers... 是intvector, realvector, realvector, intvector 又名std::vector&lt;int&gt;, std::vector&lt;Real&gt;, std::vector&lt;Real&gt;, std::vector&lt;int&gt;(我想Real 是double 的别名)。

product_iterator 的唯一可变参数构造函数是接收 Containers const&amp;... containers 的构造函数,所以我想是你想要匹配的构造函数。

在我看来,问题在于unpack_tuple()

template <class... Containers>
template <typename TupleType>
const auto& GridSearchIterator<Containers...>::unpack_tuple(TupleType &t, 
                                                            size_t index) 
{
    std::string argname;
    auto left(0), right(0);
    Size step;
    std::tie(argname, left, right, step) = t;
    argnames[index] = argname;
    auto vec = linspace(left, right, step);
    return static_cast<const decltype(vec) &>(vec);
}

返回曾经 intVector const &amp; (std::vector&lt;int&gt; const &amp;)。当使用realVector(我想是std::vector&lt;double&gt;)调用时也是如此。

这(如果我没记错的话)是因为您将 left 和 right 定义为 auto 并将它们初始化为 int

auto left(0), right(0);

当TupleType 在第二和第三位置包含Real 元素时,您也会得到几个int。

所以当你获得vec

auto vec = linspace(left, right, step);

您获得(我想)std::vector&lt;int&gt;;曾经;还有什么时候你应该获得std::vector&lt;Real&gt;。

建议:使用依赖于TupleType 的正确类型定义left 和right。

举例(注意:代码未测试)

using lr_type = typename std::tuple_element<1u, TupleType>::type;

lr_type  left, right;

从C++14开始可以使用std::tuple_element_t,`使用可以简化如下

using lr_type = std::tuple_element_t<1u, TupleType>;

如果你能用C++17,你就可以用结构化绑定,一切都会变得简单很多

template <typename TupleType>
const auto& GridSearchIterator<Containers...>::unpack_tuple(TupleType &t, 
                                                            size_t index) 
{
    auto [argname, left, right, step] = t;
    argnames[index] = argname;
    auto vec = linspace(left, right, step);
    return static_cast<const decltype(vec) &>(vec);
}

题外话:你确定这是一个好主意unpack_tuple() 将 const reference 返回到在方法执行结束时被销毁的值吗?

【讨论】:

  • @max66是的,这正是它没有编译的原因。在您建议的更改之后,现在一切正常。非常感谢!关于您的最后一条评论:这实际上是我拼命尝试解决问题的产物。我最初的实现只是返回一个右值,这是我将要使用的。
猜你喜欢
  • 2014-03-14
  • 2021-04-23
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 2016-09-12
  • 1970-01-01
  • 2020-05-11
  • 1970-01-01
相关资源
最近更新 更多