处理条件编译的多个条件的最佳方法

MrB*_*app 4 c++ templates sfinae c++14

我有一个模板类,其中有一个方法,模板参数指示该方法的输入和输出,如下所示:

template <typename In, typename Out>
class Foo
{
    Out fn(const In& in)
    {
        Out out;
        return out;
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我尝试了这个,但是当试图void用于任何一个In或那个时,会出现(可能很明显)错误Out.所以我尝试添加多个方法,这些方法是这个主题的变体,希望它们的替换能够启用相关功能并禁用无效功能:

template <std::enable_if_t<std::is_void<InputType>::value>* = nullptr>
OutputType fn()
{
    OutputType out;
    return out;
}

template <std::enable_if<(!std::is_void<OutputType>::value) && (!std::is_void<InputType>::value)>* = nullptr>
OutputType fn(InputType& t)
{
    OutputType out;
    return out;
}

template <std::enable_if<std::is_void<OutputType>::value>* = nullptr>
void fn(InputType& t)
{}
Run Code Online (Sandbox Code Playgroud)

这让我回到了"无效参考无效"领域,或者是碰撞签名.

我应该如何优雅地处理这些条件,以便从模板中只创建以下签名之一:

/*In == void && Out != void*/
Out fn(/* no input here to keep compiler happy*/) { return Out; }

/*In != void && Out != void, standard case*/
Out fn(const In& in) { return Out; }

/*In != void && Out == void*/
void fn(const In& in) { /* No returns here to keep compiler happy*/; }
Run Code Online (Sandbox Code Playgroud)

Ste*_*mer 5

您可以使用部分特化来提供Foofor In和Outvoid的实现,以及当两者都为void时的显式特化.

语法如下(注意Foo表示这是主类模板的特殊化后的尖括号Foo)

template<typename Out>
struct Foo<void, Out>  // specialisation for only In = void
{ ... };

template<typename In>
struct Foo<In, void>   // specialisation for only Out = void
{ ... };

template<>
struct Foo<void, void> // specialisation for both In and Out = void
{ ... };
Run Code Online (Sandbox Code Playgroud)

这是一个例子:

#include <iostream>

// primary class template
template <typename In, typename Out>
struct Foo {
    Out fn(const In& in) { return Out{}; }
};

// partial specialisation for when In=void
template<typename Out>
struct Foo<void, Out> {
    Out fn() { return Out{}; }
};

// partial specialisation for when Out=void
template<typename In>
struct Foo<In, void> {
    void fn(const In& in) { }
};

// explicit specialisation for when both In=void and Out=void
template<>
struct Foo<void, void> {
    void fn() { }
};

int main() {
    Foo<int, double> f;
    f.fn(5);

    Foo<void, void> g;
    g.fn();

    Foo<void, int> h;
    h.fn();

    Foo<int, void> i;
    i.fn(5);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)