强类型 C++ 可变参数

Cry*_*thm 1 c++ c++11

我正在 C++ 11 中编写一个实用函数,它将单一类型的元素添加到向量中。我发现的大多数变量参数文档/指南都显示了带有该typedef类型的模板,但我希望仅允许所有变量参数使用单一类型(const char*)。以下是相关代码片段:

项目.hpp:

// Guard removed
#include <vector>

class Item {
  public:
    Item(const char* n, bool (*optionChange)(uint8_t), const char*...);
  private:
    std::vector<const char*> options;
    void addOption(const char*);
}
Run Code Online (Sandbox Code Playgroud)

项目.cpp:

#include "Item.hpp"

void Item::addOption(const char* option) {
  options.push_back(option);
}

Item::Item(
  const char* n, 
  bool (*optionChange)(uint8_t),
  const char* opts...
): name(n), type(MENU_TYPE_OPTS), selectedOpt(0) {
  addOption(opts...); // Doesn't compile
}
Run Code Online (Sandbox Code Playgroud)

上述代码的编译失败并显示消息error: expansion pattern 'opts' contains no argument packs

for*_*818 5

使用可变参数模板。使用可变参数模板,所有类型也可以不同,但​​您可以通过 SFINAE 请求它们全部相同

#include <type_traits>
#include <tuple>

template <typename ...T>
std::enable_if_t< 
    std::is_same_v< std::tuple<const char*, T...>,
                    std::tuple<T...,const char*>>
    ,void>
foo(T...t) {}

int main() {
    const char* x;
    int y;
    foo(x,x,x,x); // OK
    foo(x,y,x); // error
}
Run Code Online (Sandbox Code Playgroud)

这是基于一个巧妙的技巧来检查可变参数包的所有类型是否都是同一类型(当我找到它时,我会将引用添加到原始版本中)。仅当所有s 均为 时std::tuple<const char*, T...>std::tuple<T...,const char*>才是同一类型。当条件(所有s are )不满足时,将放弃特化并尝试调用它会导致编译器错误。Tconst char*std::enable_ifTconst char*

这是相当老式的,并且已经在 C++11 中工作(除了_v/_t帮助程序)。我想在 C++20 中,有更少神秘的方法来要求所有Ts 都是const char*


我错过了它是一个构造函数,你不能在构造函数上执行 return-type-SFINAE 。只是需要更复杂一点:

#include <type_traits>
#include <tuple>

struct foo {
    template <typename ...T,
              std::enable_if_t< 
                   std::is_same_v< std::tuple<const char*, T...>,
                                   std::tuple<T...,const char*>
                   >,
                   bool
              > = true>
    foo(T...t) {}
};

int main() {
    const char* x;
    int y;
    foo f1(x,x,x,x); // OK
    foo f2(x,y,x); // error
}
Run Code Online (Sandbox Code Playgroud)

当满足条件时,最后一个模板参数是非类型的bool,并且具有默认值true。它的唯一目的是在不满足条件时失败(因此不需要命名)。


归档时间:

查看次数:

317 次

最近记录:

3 年,2 月 前