没有用于可变参数模板类初始化的匹配构造函数

时间:2019-05-11 16:41:56

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

我正在尝试将包装类写入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返回一个从leftright的数字向量,该向量由step的个数均匀隔开。它等效于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<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_impl<std::__1::tuple<std::__1::tuple<std::__1::basic_string<char>, int, int, unsigned long>, std::__1::tuple<std::__1::basic_string<char>, double, double, unsigned long>, std::__1::tuple<std::__1::basic_string<char>, double, double, unsigned long>, std::__1::tuple<std::__1::basic_string<char>, int, int, unsigned long> >, 0, 1, 2, 3>'请求的功能模板特化gsi.product_impl(std::tuple<TupleTypes...>(tuples...), std::index_sequence_for<TupleTypes...>{});的实例中

     

/.../ main.cpp:90:88:注意:在此处'GridSearchIterator<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> > >::initWith<std::__1::tuple<std::__1::basic_string<char>, int, int, unsigned long>, std::__1::tuple<std::__1::basic_string<char>, double, double, unsigned long>, std::__1::tuple<std::__1::basic_string<char>, double, double, unsigned long>, std::__1::tuple<std::__1::basic_string<char>, int, int, unsigned long> >'要求的功能模板特化auto grid_iter = GridSearchIterator<intvector, realvector, realvector, intvector>::initWith(std::forward<inttuple>(sidespan),的实例中

     

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

1 个答案:

答案 0 :(得分:0)

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

无论如何,这一行中都会出现错误(“无匹配的构造函数”)

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

如果我正确理解的话,Containers...就是intvector, realvector, realvector, intvector,也就是std::vector<int>, std::vector<Real>, std::vector<Real>, std::vector<int>(我认为Realdouble的别名)。

product_iterator的唯一可变参数构造函数是接收Containers const&... 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 &std::vector<int> const &)。同样,当用realVector调用时(我想是std::vector<double>)。

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

auto left(0), right(0);

int在第二和第三位置包含TupleType元素时,也会得到一对Real

因此,当您获得vec

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

您获得(我想)一个std::vector<int>;曾经以及何时应该获得std::vector<Real>

建议:使用取决于left的正确类型定义rightTupleType

通过示例(警告:代码未经测试)

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 引用到在方法执行结束时销毁的值是个好主意吗?

相关问题