【问题标题】:Recursive templated function cannot assign to variable 'state' with const-qualified type 'const tt &'递归模板函数不能分配给具有 const 限定类型“const tt &”的变量“状态”
【发布时间】:2020-02-24 04:50:39
【问题描述】:

我已将代码减少到以下最低代码:

#include<iostream>
#include<vector>

class tt
{
public:
   bool player;        
   std::vector<tt> actions;
};

template<typename state_t>
int func(state_t &state, const bool is_max)
{
   state.player = true;

   const auto &actions = state.actions;
   if(state.actions.size())
   {
      auto soln = func(actions[0], false);
   }

   return 0;
}

int main(int argc, char const *argv[])
{
   tt root;
   func(root, true);

   return 0;
}

当我尝试编译这段代码时,我得到了

test.cpp:14:17: error: cannot assign to variable 'state' with const-qualified type 'const tt &'
   state.player = true;
   ~~~~~~~~~~~~ ^
test.cpp:19:19: note: in instantiation of function template specialization 'func<const tt>' requested here
      auto soln = func(actions[0], false);
                  ^
test.cpp:28:4: note: in instantiation of function template specialization 'func<tt>' requested here
   func(root, true);
   ^
test.cpp:12:19: note: variable 'state' declared const here
int func(state_t &state, const bool is_max)
         ~~~~~~~~~^~~~~
1 error generated.

它声称状态是const tt &amp; 类型。模板化函数的签名是int func(state_t &amp;state, const bool is_max)state_t前面没有const。似乎const 是从递归调用中推导出来的,因为actionstt 对象的const-ref 向量。我认为论证推论忽略了const?这怎么会发生?

【问题讨论】:

    标签: c++ templates template-argument-deduction


    【解决方案1】:

    答案主要摘自 Scott Mayers Effective C++一书。

    template<typename T>
    void f(ParamType param);
    f(expr);                // deduce T and ParamType from expr
    

    ParamType 是引用或指针,但不是通用引用

    最简单的情况是当 ParamType 是引用类型或指针类型,而不是通用引用时。在这种情况下,类型推导的工作方式如下:

    • 如果 expr 的类型是引用,则忽略引用部分。
    • 然后将 expr 的类型与 ParamType 进行模式匹配以确定 T。

    在参数推导过程中,它忽略了引用部分而不是const 部分。

    在您的情况下,它是 const auto &amp;actions = state.actions;,这意味着,对于 auto soln = func(actions[0], false); 的模板参数推导,仅删除了引用部分,而不是 cv 限定符

    书中的更多例子。

    template<typename T>
    void f(T& param);       // param is a reference
    

    我们有这些变量声明,

    int x = 27;             // x is an int
    const int cx = x;       // cx is a const int
    const int& rx = x;      // rx is a reference to x as a const int
    the deduced types for param and T in various calls are as follows:
    
    f(x);                   // T is int, param's type is int&
    
    f(cx);                  // T is const int,
                            // param's type is const int&
    
    f(rx);                  // T is const int,
                            // param's type is const int&
    

    【讨论】:

    • 谢谢。我想我把模板的推论规则与auto 混淆了。正如您在 Meyers 书中所展示的那样,模板推导保持 const,而 auto 则没有。没关系。我想我也不在这里。我会检查并重新访问此评论。
    【解决方案2】:

    除了@aep 的回答,如果它被推导出为tt 而不是const tt,编译器也会产生错误,因为没有@987654326 就无法将const reference 绑定到non-const reference @。

    #include<iostream>
    #include<vector>
    
    class tt
    {
    public:
       bool player;        
       std::vector<tt> actions;
    };
    
    void try_to_bind_const_reference_to_non_const_reference( tt& t )
    {
    
    }
    
    template<typename state_t>
    int func(state_t &state, const bool is_max)
    {
       state.player = true;
    
       const auto &actions = state.actions;
       if(state.actions.size())
       {
          // auto soln = func(actions[0], false);
          try_to_bind_const_reference_to_non_const_reference( actions[0] );
       }
    
       return 0;
    }
    
    int main(int argc, char const *argv[])
    {
       tt root;
       func(root, true);
    
       return 0;
    }
    

    run online

    【讨论】:

      猜你喜欢
      • 2016-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-12
      相关资源
      最近更新 更多