将函数参数限制为某些枚举值

时间:2017-06-30 10:38:05

标签: c++ c++11 templates c++14 c++17

这是我的第一次尝试 -

#include <iostream>
using namespace std;

enum class props {
    left, right
};

template<typename T>
auto allowLeftOnly(T p) -> decltype((p==props::left), void())
{
    cout << "Wow!";
}

int main() {
    props p1 = props::left;
    props p2 = props::right;
    allowLeftOnly(p1);
    // allowLeftOnly(p2);  // should fail to compile
}

我希望allowLeftOnly函数只接受props::left或其他我明确指定为参数而不能为其他人编译的人。这可能吗?

3 个答案:

答案 0 :(得分:4)

不,这是不可能的。 p1p2的值是运行时属性,而不是编译时属性,因此编译器不会知道&#34;他们在编译时的价值观。

您可以使用constexpr在编译时将它们告知,并将它们作为模板参数传递,例如:

#include <iostream>
#include <type_traits>

enum class props {
    left, right
};

template <props v>
typename std::enable_if<v == props::left, void>::type allowLeftOnly()
{ std::cout << "Wow!\n"; }

int main() {
    constexpr auto p1 = props::left;
    constexpr auto p2 = props::right;
    allowLeftOnly<p1>();
    allowLeftOnly<p2>(); // Fails to compile
}

答案 1 :(得分:3)

您可以将p更改为模板参数,然后使用std::enable_if,如下所示:

template <props p> // p is now a template parameter
std::enable_if_t<p == props::left> // We only allow p == props::left, return type is implicitly void
allowLeftOnly() // No 'normal' parameters anymore
{
    std::cout << "Wow!";
}

int main()
{
    constexpr props p1 = props::left;
    constexpr props p2 = props::right;
    allowLeftOnly<p1>();
    // allowLeftOnly<p2>();  // Fails to compile
}

对于p1p2constexpr关键字可确保我们可以将变量用作模板参数。

如果您以后想要其他退货类型,例如int,请使用:

std::enable_if_t<p == props::left, int>

答案 2 :(得分:1)

正如其他答案建议使用模板参数一样,我还会添加一个答案,说明如何使用标记调度(description from boost.org)来实现这一点:

#include <iostream>
using namespace std;

struct props
{
    struct left {};
    struct right {};
};

void allowLeftOnly(props::left p)
{
    cout << "Wow!";
}

int main()
{
    allowLeftOnly(props::left{});
    // allowLeftOnly(props::right{});  // Fails to compile
}