【问题标题】:Convert C Array to Variadic Template Argument将 C 数组转换为可变参数模板参数
【发布时间】:2019-02-27 19:27:36
【问题描述】:

我一直在探索 CPP,想知道这是否可行:

一个可变参数模板类,将 N 个元素的数组转换为带有可变参数列表的函数调用。

例如,如果给定一个这样的数组

argc = 3, args = { "hello", "10", "0.5" }

我的愿望是能够这样打电话

Something<std::string, int, float>(3, args);

这将做一些处理以使用转换后的参数调用函数

我之前探索过的资源是尝试使用 C++14 的表达式折叠或尝试使用递归模板。我认为必须使用参数包和一些定义来转换它。到目前为止,这是我的代码

假设要将 C 字符串数组转换为参数,我创建了许多转换结构

这里我有一个结构来将 char*(数组的元素)转换为一些未知参数

// generic conversion
template <typename T>
struct convert {
  T operator()(char const*) const;
};

// specific convert char* to std::string
template <>
struct convert<std::string> {
  std::string operator()(char const* str) const {
    return std::string(str);
  }
};

// many different convert<> structs for different types...

这就是问题所在。在这个类中,我尝试构建 C 字符串的 N 个元素的任意转换器的表示

class Handler {
public:
  virtual bool Handle(int argc, char const** argv);
};

template <typename... Args>
class Command : public Handler {
protected:
  bool Execute(Args... args);

public:
  bool Handle(int argc, char const** argv) override {
    if (argc != sizeof...(Args))
      return false;
    // HELP call convert<> on each type in args then call Execute();
  }
};

对于我的帮助,我探索其他问题尝试参数解包或表达式折叠,但它不喜欢他。

例如命令的一种实现是

class Help : public Command<std::string> {
public:
  bool Execute(std::string sub) {

  }
};

我也尝试使用 CPP14 索引序列,但我的问题是在索引序列中有两个“数组”进行迭代。 char** 和可变参数模板。

谢谢!

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    使用可变参数模板,您可以在一个模式中扩展多个包。

    您可以使用它来获得args 数组的索引和参数包中的类型。

    解决办法如下:

    #include <type_traits>
    #include <utility>
    #include <string>
    
    template<typename T>
    struct Convert {
        auto operator()(char const*) -> T {
            return T{};
        }
    };
    
    template<typename... Args>
    struct Command {
        bool execute(Args...) {
            return true;
        }
    
        bool handle(int argc, char const** args) {
            // This should be a precondition
            if (argc != sizeof...(Args)) { 
                return false;
            }
    
            auto sequence = std::index_sequence_for<Args...>{};
            return handleImpl(sequence, args);
        }
    
        template<std::size_t... S>
        bool handleImpl(std::index_sequence<S...>, char const** args) {
            // both S and Args expanded
            return execute(Convert<Args>{}(args[S])...);
        }
    };
    
    int main() {
        Command<int, std::string, double> c;
    
        char const* args[] = {"1", "blah", "1.2"};
    
        c.handle(3, args);
    }
    

    Live Example

    【讨论】:

    • ~这是使用索引序列结合表达式折叠吗?~我现在看到你的评论了
    • 我看到转换正在发生,但是如何调用 Execute 进行这种转换?再使用一个参数包?
    • tnx 寻求帮助。我想做的是在所有参数上调用 Execute() 。在handleImpl中,我尝试使用参数包来做到这一点Execute({(parameter&lt;Args&gt;{}(args[S]), ...)});。这个编译,但我不确定它是否正确。到目前为止,tnx 寻求帮助!
    • @GuillaumeRaciocot 似乎无法编译,但这可以通过使用原始答案并转换为打包参数Execute({(convert&lt;Args&gt;{}(args[S]), ...)}) 来工作。编辑:实际上这不适用于多个模板参数
    • @ObveyMyshka 更新了示例。它适用于我的多个参数。
    猜你喜欢
    • 2014-04-30
    • 1970-01-01
    • 2013-10-13
    • 2017-08-07
    • 1970-01-01
    • 2021-06-04
    • 2011-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多