如何省略C++中不同参数的复制函数定义

Esa*_*ier 3 c++ parameter-passing c++14

我有很多代码以某种方式执行完全相同的操作(继承的代码),并且我希望在重新编写代码时压缩代码而不会丢失功能.例如,让我们看看以下函数:

fnc(largetype & a,  largetype & b)  { f(A); f(B); };
fnc(largetype && a, largetype & b)  { f(A); f(B); };
fnc(largetype & a,  largetype && b) { f(A); f(B); };
fnc(largetype && a, largetype && b) { f(A); f(B); };
Run Code Online (Sandbox Code Playgroud)

所有这些都做了完全相同的事情,但参数可以是rvalues或lvalues而不会破坏函数逻辑.我希望允许用户传递任何适合问题的内容,但我也不想一块一块地复制粘贴所有代码.我可以这样做:

fnc(largetype & a,  largetype & b)  { f(A); f(B); };
fnc(largetype && a, largetype & b)  { fnc(a,b) };
fnc(largetype & a,  largetype && b) { fnc(a,b) };
fnc(largetype && a, largetype && b) { fnc(a,b) };
Run Code Online (Sandbox Code Playgroud)

这在技术上是正确的,尤其是内联,但对我来说似乎不对.有没有其他更好的方法来实现这样的效果?

唯一的要求是作为参数传递的类型可能/将以某种方式大于默认存储器块大小,因此复制避免是至关重要的.还有一个非零的机会,参数可以更小,但也是一个右值.线程安全是可选的.

我考虑模仿这些功能,但我认为这也是错误的方法.模板解决了不同接受类型的问题.在我的情况下,类型是相同的,只以不同的方式传递.

ild*_*arn 5

正如@SamVarshavchik评论的那样,这是完美转发的常用候选者.一个简单的方法:

template<typename T, typename U>
void fnc(T&& a, U&& b)
{
    f(std::forward<T>(a));
    f(std::forward<U>(b));
}
Run Code Online (Sandbox Code Playgroud)

如果用户传入非类型的对象largetype,则错误站点将在此功能中,这可能会使用户感到困惑.要将错误站点推送到调用者的代码,我们可以使用SFINAE来约束参数类型:

template<
    typename T, typename U,
    typename = std::enable_if_t<
        std::is_same<std::decay_t<T>, largetype>{}
     && std::is_same<std::decay_t<U>, largetype>{}
    >
>
void fnc(T&& a, U&& b)
{
    f(std::forward<T>(a));
    f(std::forward<U>(b));
}
Run Code Online (Sandbox Code Playgroud)

Online Demo

或者,您可能希望将错误站点保留在其中fnc但提供更清晰的错误消息 - 这可以通过以下方式完成static_assert:

template<typename T, typename U>
void fnc(T&& a, U&& b)
{
    static_assert(std::is_same<std::decay_t<T>, largetype>{},
                  "argument 'a' must be of type 'largetype'");
    static_assert(std::is_same<std::decay_t<U>, largetype>{},
                  "argument 'b' must be of type 'largetype'");

    f(std::forward<T>(a));
    f(std::forward<U>(b));
}
Run Code Online (Sandbox Code Playgroud)

Online Demo