C ++:可变参数模板和函数重载

文斯

参见下面的示例直播:https : //onlinegdb.com/Hkg6iQ3ZNI

#include <iostream>
#include <utility>
#include <type_traits>

class A 
{
    public:
    A(int v=-10):v_(v){}
    void print()
    {
        std::cout << "called A: " << v_ << std::endl;
    }
    private:
    int v_;
};

void f(int v)
{
    std::cout << "called f: " << v << std::endl;
    
}


template<typename T,typename ... Args>
void run(A&& a,
         T&& t,
         Args&& ... args)
{
    a.print();
    t(std::forward<Args>(args)...);
}


template<typename T,typename ... Args>
void run(T&& t,
          Args&& ... args)
{
  run(A(),
      std::forward<T>(t),
      std::forward<Args>(args)...);
}

int main()
{
    int v_function=1;
    int v_a = 2;
    
    run(f,v_function);
    
    return 0;
}

上面的代码编译,运行和打印(按预期):

称为A:-10

称为f:1

但是如果将main函数修改为:

int main()
{
    int v_function=1;
    int v_a = 2;
    
    run(f,v_function);
    
    // !! added lines !!

    A a(v_a);
    run(a,f,v_function);
    
    return 0;
}

然后编译失败并显示错误:

main.cpp:30:6:错误:调用'(A)(void(&)(int),int&)'不匹配

t(std :: forward(args)...);

〜^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~

这似乎表明,即使将A的实例作为第一个参数传递,重载函数

void(*)(T&&,Args&&...) 

被称为,而不是

void(*)(A&&,T&&,Args&&...) 
内森·奥利弗

template<typename T,typename ... Args>
void run(A&& a,
         T&& t,
         Args&& ... args)

a不是转发参考,而是右值参考。这意味着您执行run(a,f,v_function);该操作时将不会选择该函数,因为它a是一个左值,并且这些函数无法绑定到右值引用。有两种快速的方法可以解决此问题。首先,std::movealike上使用

run(std::move(a),f,v_function);

但这不是很好。a实际上并未在函数中移动,因此您有点违反了最小惊讶原则。

第二种选择是A在函数中创建模板类型,使其成为转发引用,然后可以将其限制为A类似

template<typename A_, typename T,typename ... Args, std::enable_if_t<std::is_same_v<std::decay_t<A_>, A>, bool> = true>
void run(A_&& a,
         T&& t,
         Args&& ... args)
{
    a.print();
    t(std::forward<Args>(args)...);
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章