【问题标题】:char unexpected behaviour with templated methodschar 模板化方法的意外行为
【发布时间】:2018-04-06 23:54:38
【问题描述】:

我正在研究一个应该(因为它的硬件)由可变参数模板解决的问题。我缺乏理解使我无法解决以下错误。

代码是:

#include <sstream>
#include <iostream>
#include <string>
#include <vector>
#include <tuple>

template<typename ... TL>
class LazySplitResult
{
public:
    LazySplitResult(TL ...pl) :storedParams(pl ...) {       }

    void doStuff()
    {
        // invoke method with inside parameters
        useStoredTuple(storedParams, std::index_sequence_for<TL...>());
    }
    template<typename T, typename T1, typename... Targs>
    void doInsideLogic(T&& value1, Targs&&  ... Fargs)
    {
        // there is some logic
        // for example this
        std::stringstream convert("0");
        // it works for string,double,int ... other types are not supported
        // so exception would be in place
        convert >> value1;
    }

    void doInsideLogic()
    {
    }       

private:
    template<std::size_t... Is>
    void useStoredTuple(const std::tuple<TL ...>& tuple,std::index_sequence<Is...>) {
        wrapInsideLogic(std::get<Is>(tuple) ...);
    }

    void  wrapInsideLogic(TL && ... args)
    {
        doInsideLogic(args...);
    }

    std::tuple<TL ...> storedParams;
};

template<typename ...TL>
LazySplitResult<TL ...> getResult(TL && ...pl)
{
    return LazySplitResult<TL...>(pl  ...);
}

int main()
{
    std::string x;
    int y;
    double z;

    // prepares an object
    auto lazyResult=getResult(x, '.', '-', y, 'x', z , 'a');

    // let it do its thing and set unset variables
    lazyResult.doStuff();

    std::cout << "x = " << x << ", y = " << y << ", z = " << z << std::endl;

    return 0;
}

错误信息在这里

error C2664: 'void LazySplitResult<std::string &,char,char,int &,char,double &,char>::wrapInsideLogic(std::string &,char &&,char &&,int &,char &&,double &,char &&)': cannot convert argument 2 from 'const char' to 'char &&'
source_file.cpp(40): note: Conversion loses qualifiers
source_file.cpp(18): note: see reference to function template instantiation 'void LazySplitResult<std::string &,char,char,int &,char,double &,char>::useStoredTuple<0,1,2,3,4,5,6>(const std::tuple<std::string &,char,char,int &,char,double &,char> &,std::integer_sequence<_Ty,0,1,2,3,4,5,6>)'

复制自rextester here

HW 的主要部分是解析公式并将结果保存在变量中,如下所示:

// declare variables and initialize class with formula

parse(x, '.', '-', y, 'x', z , 'a');   
std::cout << "x = " << x << ", y = " << y << ", z = " << z << std::endl;

代码的作用相同,只是它以惰性方式执行,因此需要将参数存储在元组中以供以后使用。

我尝试实现相同的逻辑,除了懒惰,没有成功地使用元组和类。可以观察here。没有引发错误描述转换错误。

你能帮帮我吗?我完全迷路了。入口方法调用相同,处理参数的可变参数模板方法具有相同的参数......唯一的区别似乎是元组和类之间。

【问题讨论】:

  • 您没有向我们提供相关代码:大概,xyz 是 const-qualified(或其他限定符),因此不能在不丢失限定符的情况下调用.

标签: c++ templates variadic-templates implicit-conversion stdtuple


【解决方案1】:

首先,你的doInsideLogic函数模板中有一个无用的模板参数T1。删除它。

wrapInsideLogic 的参数不是转发引用,因为TL 是已知的且无法推断。它的参数std::get&lt;Is&gt;(tuple)const TL&amp; 类型,因为tupleconst std::tuple&lt;TL...&gt;&amp; 类型,因此与参数类型TL&amp;&amp; 不匹配。要解决此问题,有两种选择:

  1. 使用转发引用,即

    template <typename... Targs>
    void wrapInsideLogic(Targs&&... args)
    {
        doInsideLogic(std::forward<Targs>(args)...);
    } 
    
  2. 使用对 const 的引用,即

    void wrapInsideLogic(const TL&... args)
    {
        doInsideLogic(args...);
    } 
    

【讨论】:

    【解决方案2】:

    不确定...您是为第一个链接引用的代码还是第二个链接引用的代码寻求帮助?

    我想是第二个代码所以我建议重新排序函数的定义如下。

    首先是递归的基本情况

    void myFunc ()
     { std::cout << "end" << std::endl; }
    

    二、myFunc()的递归版本

    template <typename T, typename ... Targs>
    void myFunc (T && value1, Targs && ... Fargs)
     {
       // there should be additional logic 
       // if value1 is char then skip it. But it was intentionally ommited
       std::cout << " do" << std::endl;
    
       const char* parsedValue = "0";
       std::stringstream convert(parsedValue);
       // cast current value according to thing.
       convert >> value1;
    
       myFunc(Fargs ...);
     }
    

    第三,test()

    template <typename ... Targs>
    void test (Targs && ... args)
     { myFunc(args...); }
    

    现在您的代码应该可以编译了。

    如果你先写test(),然后是递归myFunc(),最后是基本情况myFunc(),你有(1)test()在未声明时调用myFunc()和(2)递归myFunc()未声明时调用地面案例myFunc()

    【讨论】:

    • 第二个 rextester 链接中的代码可以按我的意愿工作。第一个链接中的另一个没有。任务是让它工作并产生相同的结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-08
    • 2014-03-20
    • 1970-01-01
    • 2016-01-16
    • 1970-01-01
    • 2023-02-26
    相关资源
    最近更新 更多