Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/161.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 对于std::any-like容器,是否可以转发具有匹配模板类型的函数调用?_C++_Templates_Design Patterns_Stdbind_Stdany - Fatal编程技术网

C++ 对于std::any-like容器,是否可以转发具有匹配模板类型的函数调用?

C++ 对于std::any-like容器,是否可以转发具有匹配模板类型的函数调用?,c++,templates,design-patterns,stdbind,stdany,C++,Templates,Design Patterns,Stdbind,Stdany,我还没有找到一个方法来实现我想要的,但我没有足够的知识来知道这是否是不可能的。我们将不胜感激 我们软件中的主数据容器的行为有点像std::variant或std::any:它有一个提供类型枚举的基类BaseContainer。派生实例DataContainer将实际数据保存在类型化的张量成员变量中。因此,一个简化的示例可以归结为如下内容: // One like this for each function. struct ProcessDataWrapper { template <

我还没有找到一个方法来实现我想要的,但我没有足够的知识来知道这是否是不可能的。我们将不胜感激

我们软件中的主数据容器的行为有点像std::variant或std::any:它有一个提供类型枚举的基类
BaseContainer
。派生实例
DataContainer
将实际数据保存在类型化的张量成员变量中。因此,一个简化的示例可以归结为如下内容:

// One like this for each function.
struct ProcessDataWrapper {
  template <typename... Args>
  static auto run(Args&&... args) {
    return processData(std::forward<Args>(args)...);
  }
};

template <typename Wrapper>
auto ProcessGeneric(BaseContainer* aContainer) {
    switch (vContainer->getType()) {
        case DataTypes::INT8:
            return Wrapper::run(dynamic_cast<DataContainer<int8_t>>(vContainer)->getData());
    // ...
}

// Called as
ProcessGeneric<ProcessDataWrapper>(myContainer);
BaseContainer*vContainer=新的数据容器({1000000});
如果(vContainer->getType()==DataTypes::FLOAT)
常量张量&vTensor=dynamic_cast(vContainer)->getData();
我们有许多基于基础模板类型和维度处理数据的方法:

模板
void processData(常量张量和aTensor,…其他参数…);
问题是,对于我们希望使用
BaseContainer
调用的每个方法,如
processData()
,我们需要编写一个绑定方法,该方法分解调用
processData()
类型版本的可能类型:

void processData(BaseContainer*a容器){
开关(vContainer->getType()){
案例数据类型::INT8:
返回processData(dynamic_cast(vContainer)->getData());
案例数据类型::UINT8:
返回processData(dynamic_cast(vContainer)->getData());
案例数据类型::INT16:
返回processData(dynamic_cast(vContainer)->getData());
案例数据类型::UINT16:
返回processData(dynamic_cast(vContainer)->getData());
...
违约:
抛出(std::runtime_错误(“不支持类型”);
}
}
我的问题是:是否可以创建一个“适配器”方法(在任何已发布的c++版本中),该方法可以接受一个函数(如
processData()
)、一个BaseContainer和一个可能的参数列表,并用参数调用此函数的正确模板绑定

我无法动态绑定模板函数,因为在没有模板类型的情况下无法传递名称。然而,模板类型需要基于BaseContainer是动态的。但也许还有其他方法来实现我想做的事情?我对任何解决方案都很好奇,主要是为了扩展我的理解,只要解决方案的复杂性低于编写数百个适配器方法


如果没有其他内容,是否可以使用预处理器宏生成“适配器”方法?

如果您愿意为每个类似于
processData
的函数编写一个小包装类,可以执行以下操作:

// One like this for each function.
struct ProcessDataWrapper {
  template <typename... Args>
  static auto run(Args&&... args) {
    return processData(std::forward<Args>(args)...);
  }
};

template <typename Wrapper>
auto ProcessGeneric(BaseContainer* aContainer) {
    switch (vContainer->getType()) {
        case DataTypes::INT8:
            return Wrapper::run(dynamic_cast<DataContainer<int8_t>>(vContainer)->getData());
    // ...
}

// Called as
ProcessGeneric<ProcessDataWrapper>(myContainer);
//每个函数有一个这样的函数。
结构ProcessDataWrapper{
模板
静态自动运行(Args&&…Args){
返回processData(std::forward(args)…);
}
};
模板
自动处理通用(基本容器*容器){
开关(vContainer->getType()){
案例数据类型::INT8:
返回包装器::run(dynamic_cast(vContainer)->getData();
// ...
}
//称为
过程通用(myContainer);

如果您愿意为每个类似于
processData
的函数编写一个小包装类,您可以这样做:

// One like this for each function.
struct ProcessDataWrapper {
  template <typename... Args>
  static auto run(Args&&... args) {
    return processData(std::forward<Args>(args)...);
  }
};

template <typename Wrapper>
auto ProcessGeneric(BaseContainer* aContainer) {
    switch (vContainer->getType()) {
        case DataTypes::INT8:
            return Wrapper::run(dynamic_cast<DataContainer<int8_t>>(vContainer)->getData());
    // ...
}

// Called as
ProcessGeneric<ProcessDataWrapper>(myContainer);
//每个函数有一个这样的函数。
结构ProcessDataWrapper{
模板
静态自动运行(Args&&…Args){
返回processData(std::forward(args)…);
}
};
模板
自动处理通用(基本容器*容器){
开关(vContainer->getType()){
案例数据类型::INT8:
返回包装器::run(dynamic_cast(vContainer)->getData();
// ...
}
//称为
过程通用(myContainer);

这是可能的,但正如评论所说,它可能值得访问

这里有一个需要c++17的解决方案,每个要包装的函数模板只需要两行代码。您可以使用一个简单的宏来进一步简化包装

其核心思想是拥有一个
cast
函数,该函数将
数据类型
枚举映射到相应的
数据容器
,然后利用c++17折叠表达式将switch语句包装到代码中

这里是
cast
函数,因此我们正好有一个位置可以从
DataType
映射到活动
DataContainer

template<DataType t>
constexpr inline decltype(auto) cast(BaseContainer& c) {
    if constexpr(t == INT) return static_cast<DataContainer<int>&>(c);
    else if constexpr(t == FLOAT) return static_cast<DataContainer<float>&>(c);
    ... map all other enum values ...
}
//每个功能都需要这样做: auto-pd=data_type_dispatcher([](auto&c,int-arg){processData(c,arg);})

intmain(){
数据容器f;
数据容器i;
pd(f,2);//打印浮点,2
pd(i,4);//打印int,4
}
完整的例子

要在不支持该类型时引发异常,只需添加在折叠表达式末尾引发的lambda:

    ([&]{ if(c.GetDataType() == types ) {  std::invoke(f, cast<types>(c), args...); return true; } return false; }() || ...  || []() -> bool{ throw (std::runtime_error("Type not supported")); }());
                                                                                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
([&]{if(c.GetDataType()==types){std::invoke(f,cast(c),args…;return true;}return false;}()| |·····································;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

这是可能的,但正如评论所说,它可能值得访问

这里有一个需要c++17的解决方案,每个要包装的函数模板只需要两行代码。您可以使用一个简单的宏来进一步简化包装

其核心思想是拥有一个
cast
函数,该函数将
数据类型
枚举映射到相应的
数据容器
,然后利用c++17折叠表达式将switch语句包装到代码中

这里是
cast
函数,因此我们正好有一个位置可以从
DataType
映射到活动
DataContainer

template<DataType t>
constexpr inline decltype(auto) cast(BaseContainer& c) {
    if constexpr(t == INT) return static_cast<DataContainer<int>&>(c);
    else if constexpr(t == FLOAT) return static_cast<DataContainer<float>&>(c);
    ... map all other enum values ...
}
//每个功能都需要这样做: auto pd=data\u type\u dispatcher([](auto&c,int arg){processData(c,ar)
template <typename F>
auto dispatch(BaseContainer& vContainer, F f) {
    switch (vContainer.getType()) {
        case DataTypes::INT8:
            return f(dynamic_cast<DataContainer<int8_t>&>(vContainer).getData());
        case DataTypes::UINT8:
            return f(dynamic_cast<DataContainer<uint8_t>&>(vContainer).getData());
        case DataTypes::INT16:
            return f(dynamic_cast<DataContainer<int16_t>&>(vContainer).getData());
        case DataTypes::UINT16:
            return f(dynamic_cast<DataContainer<uint16_t>&>(vContainer).getData());
...
        default:
            throw (std::runtime_error("Type not supported"));
    }
}

dispatch(vContainer, [](auto* data){ return processData(data); });