【问题标题】:Is there a good way to enforce type restrictions on function parameters in a variadic template in C++?有没有一种好方法可以对 C++ 中的可变参数模板中的函数参数实施类型限制?
【发布时间】:2015-11-10 23:16:55
【问题描述】:

我有一个枚举,我们称之为类型。它的值如下:

enum Type { STRING, TYPE_A_INT, TYPE_B_INT};

我想编写一个函数 Foo,它可以采用任意多个 {int, string} 类型的值,但强制模板参数与参数类型匹配。

理想情况下,它的行为如下:

Foo<STRING, TYPE_A_INT>("str", 32); // works
Foo<STRING, TYPE_B_INT>("str", 32);  // works
Foo<STRING, TYPE_B_INT, TYPE_A_INT, STRING>("str", 32, 28, "str");  // works
Foo<STRING, TYPE_B_INT>("str", "str");  // doesn't compile

有没有办法做到这一点?

似乎我可以执行以下操作,但这不起作用,因为 Args 将是 Type 而 args 将是 {string, int}。

template<typename Arg, typename... Args>
std::enable_if<(std::is_same<Arg, STRING>::value)> 
Foo(String arg, Args... args) {
    // Do stuff to arg, then make recursive call.
    Foo(args);
}

template<typename Arg, typename... Args>
std::enable_if<(std::is_same<Arg, TYPE_A_INT>::value)> 
Foo(int arg, Args... args) {
    // Do stuff to arg, then make recursive call.
    Foo(args);
}

我可以将参数包装成类似

pair<Type, string>
pair<Type, int>

但最好避免这种情况。

【问题讨论】:

  • Do stuff to arg 部分中,如果该类型无论如何都不起作用,它不会有编译器错误吗?当编译器应该为您执行此操作时,您为什么需要限制它?
  • 为什么不在使用std::is_same 的模板函数中实现static_assert 来要求允许的类型之一?

标签: c++ variadic-templates variadic-functions enable-if


【解决方案1】:

一种简单的方法是创建一个从枚举数到所需类型的映射,并使用它来构建函数参数列表 - 我猜你可以将其视为“枚举数特征”:

#include <iostream>
#include <string>

enum Type {STRING, TYPE_A_INT, TYPE_B_INT};

template<Type> struct type_from;

template<> struct type_from<STRING> { using type = std::string; };
template<> struct type_from<TYPE_A_INT> { using type = int; };
template<> struct type_from<TYPE_B_INT> { using type = int; };

template<Type E> using type_from_t = typename type_from<E>::type;

template<Type... Es> void Foo(type_from_t<Es>... args)
{
   // Do stuff with args.
   using expander = int[];
   (void)expander{0, (std::cout << args << ' ', 0)...};
   std::cout << '\n';
}

int main()
{
   Foo<STRING, TYPE_A_INT>("str", 32); // works
   Foo<STRING, TYPE_B_INT>("str", 32);  // works
   Foo<STRING, TYPE_B_INT, TYPE_A_INT, STRING>("str", 32, 28, "str");  // works
   // Foo<STRING, TYPE_B_INT>("str", "str");  // doesn't work
}

如果您取消注释最后一行,您将收到一条很好的错误消息,告诉您究竟是什么参数导致了问题。

当然,这并不能确保函数参数类型与枚举器特征给出的完全一致,而是确保它们中的每一个都有一个有效的隐式转换。据我了解,这就是您想要的,因为您的示例将字符串文字传递给std::strings。

【讨论】:

    猜你喜欢
    • 2016-05-08
    • 1970-01-01
    • 1970-01-01
    • 2021-12-17
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多