完美转发模板C ++类内部的函数 [英] Perfect forwarding for functions inside of a templated C++ class

查看:41
本文介绍了完美转发模板C ++类内部的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一种很好的方法来获得模板类内部函数的完美转发?具体来说,在代码中

Is there a good way to get perfect forwarding for functions inside of a templated class? Specifically, in the code

#include <iostream>

// Forward declare a Bar
struct Bar;

// Two different functions that vary based on the kind of argument
void printme(Bar const & bar) {
    std::cout << "printme: constant reference bar" << std::endl;
}
void printme(Bar && bar) {
    std::cout << "printme: r-value reference bar" << std::endl;
}

void printme2(Bar const & bar) {
    std::cout << "printme2: constant reference bar" << std::endl;
}
void printme2(Bar && bar) {
    std::cout << "printme2: r-value reference bar" << std::endl;
}

// Some class with a bunch of functions and possible some data (though, not
// in this one)
template <typename T>
struct Foo {
    void baz(T && t) {
        printme(std::forward <T> (t)); 
    }
    void buz(T && t) {
        printme2(std::forward <T> (t)); 
    }
};

struct Bar {};

int main() {
    Foo <Bar> foo;        
    foo.baz(Bar());

    // Causes an error
    Bar bar;
    //foo.buz(bar);
}

取消注释最后的代码,我们得到以下错误:

Uncommenting the last bit of code, we get the error:

    test03.cpp: In function 'int main()':
    test03.cpp:51:16: error: cannot bind 'Bar' lvalue to 'Bar&&'
         foo.buz(bar);
                    ^
    test03.cpp:30:10: note: initializing argument 1 of 'void Foo<T>::buz(T&&) [with T = Bar]'
         void buz(T && t) {
              ^
    Makefile:2: recipe for target 'all' failed
    make: *** [all] Error 1

现在,我们可以通过将模板参数移至类内部来解决此问题:

Now, we can fix this problem by moving the template argument inside of the class:

#include <iostream>

// Forward declare a Bar
struct Bar;

// Two different functions that vary based on the kind of argument
void printme(Bar const & bar) {
    std::cout << "printme: constant reference bar" << std::endl;
}
void printme(Bar && bar) {
    std::cout << "printme: r-value reference bar" << std::endl;
}

void printme2(Bar const & bar) {
    std::cout << "printme2: constant reference bar" << std::endl;
}
void printme2(Bar && bar) {
    std::cout << "printme2: r-value reference bar" << std::endl;
}

// Some class with a bunch of functions and possible some data (though, not
// in this one)
template <typename T>
struct Foo {
    void baz(T && t) {
        printme(std::forward <T> (t)); 
    }
    template <typename T_>
    void buz(T_ && t) {
        printme2(std::forward <T_> (t)); 
    }
};

struct Bar {
    Bar() {} 
};

int main() {
    Foo <Bar> foo;        
    foo.baz(Bar());

    Bar bar;
    foo.buz(bar);
}

但是,这似乎真的很冗长.例如,假设我们有大量的函数都依赖于 T 类型,并且需要完美的转发.我们将需要为每个模板分别声明模板.另外,类 Foo 可能包含类型为 T 的数据,我们需要与该数据一致的函数.当然,类型检查器会捕获不匹配的内容,但是该系统并不像只有一个模板参数 T 那样简单.

However, this seems like it'll be really verbose. For example, imagine that we have a large number of functions that all depended on the type T and needed perfect forwarding. We'll need separate template declarations for each. Also, the class Foo may contain a data of type T and we want functions that are consistent with this data. Certainly, the typechecker will catch mismatches, but this system isn't as straightforward as just having a single template argument, T.

基本上,我想知道的是,是否有更好的方法可以做到这一点,还是我们只是单独对类中的每个函数进行模版设计?

Basically, what I'm wondering is if there's a better way to do this or are we stuck just templating each function in the class separately?

推荐答案

模板非常不同.

在第一个代码中,您的模板参数是 Bar ,所以我也不知道它在做什么,因为您不应该使用 std :: forward 引用合格类型除外.我认为 void buz(Bar& t){printme((Bar)t);} ,编译器对传递左值 bar犹豫不决(在 main 中)到需要 Bar&& 的函数.

In the first code, your template parameter is Bar, and so I'm not sure even what it's doing, because you should NOT be using std::forward except with reference-qualified-types. I think it's void buz(Bar&& t) {printme((Bar)t);}, and the compiler is balking at passing the lvalue bar in main to a function expecting Bar&&.

在第二个代码块中,由于通用引用,模板参数为 Bar& ,因此代码为 void buz(Bar& t){printme((Bar& t));} ,它可以绑定到 main 中的左值 bar .

In the second codeblock, the template parameter is Bar& due to the universal reference, so the code is void buz(Bar& t) {printme((Bar&)t);}, which binds to to the lvalue bar in main just fine.

如果要完美转发,则模板参数必须是要传递的右值限定类型,这意味着几乎总是必须将函数本身进行模板化.但是,帮自己一个忙,给它起个不同的名字. T T _ 将是不同类型.

If you want perfect forwarding, the template parameter must be the rvalue-qualified type you want passed on, which means you almost always have to have the function itself be templated. However, do yourself a favor and name it different. The T and the T_ will be different types.

template <typename U>
void buz(U&& t) {
    printme2(std::forward<U>(t)); 
}

如果您需要SFINAE,也可以添加它:

If you want SFINAE, you can add that too:

template <typename U,
    typename allowed=typename std::enable_if<std::is_constructible<Bar,U>::value,void*>::type
    >
void buz(U && t) {
    printme2(std::forward <U> (t)); 
}

这篇关于完美转发模板C ++类内部的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆