简体   繁体   English

如何转发元组的类型以专门化其他模板?

[英]how to forward the types of tuple to specialize other template?

currently I'm working on a dynamic container structure, which represents one pod value or has vector of pointers with same container type. 目前我正在研究一个动态容器结构,它代表一个pod值或者具有相同容器类型的指针向量。 The container has an interface optional<T> expect_value<T>() 。 For pod types the implemention is simple. 容器有一个接口optional<T> expect_value<T>() 。对于pod类型,实现很简单。 For the non pod value, I would call expect_value<tuple<args...>>() , the args would be tuple as well. 对于非pod值,我将调用expect_value<tuple<args...>>()args也将是元组。 But when implement this function, I come across a trouble: how to redirect a.expect_value<tuple<args...>>() to a.expect_value_tuple<args...>>() . 但是当实现这个函数时,我遇到了一个麻烦:如何将a.expect_value<tuple<args...>>()重定向到a.expect_value_tuple<args...>>() For example, the call to a.expect_value<tuple<int,int>() would return the result of a.expect_value_tuple<int, int>() . 例如,对a.expect_value<tuple<int,int>()的调用将返回a.expect_value_tuple<int, int>() Because the argument is empty, I cant use the type deduce of unpacked arguments. 因为参数是空的,所以我不能使用解压缩参数的类型推导。 Then the whole project just cant progress any more. 然后整个项目再也无法进展了。 Any ideas? 有任何想法吗? Below is the minimal example for my intention. 以下是我的意图的最小例子。

#include <tuple>
#include <vector>
#include <optional>
#include <functional>

using namespace std;

template<typename T>
struct is_tuple_impl : std::false_type {};

template<typename... Ts>
struct is_tuple_impl<std::tuple<Ts...>> : std::true_type {};

template<typename T>
struct is_tuple : is_tuple_impl<std::decay_t<T>> {};

class my_container;

template<typename... args, size_t... arg_idx>
optional<tuple<args>...> get_tuple_value_from_vector(const vector<my_container*>& v_list, std::index_sequence<arg_idx...>)
{
    auto temp_result = make_tuple((*v_list[arg_idx]).expect_value<arg>()...);

    if(!(get<arg_idx>(temp_result) &&...))
    {
        return nullopt;
    }
    return make_tuple(get<arg_idx>(temp_result).value()...);

}

class my_container
{
public:
    int value_type; // 1 for v_int 2 for v_list 0 empty
    union
    {
        int v_int;
    };
    vector<my_container*> v_list;
    template<typename T> 
    optional<T> expect_simple_value();
    template<typename... args>
    optional<tuple<args...>> expect_tuple_value();
    template<typename T> 
    optional<T> expect_value();
};
template <typename T>
optional<T> my_container::expect_simple_value()
{
    return nullopt;
}

template <>
optional<int> my_container::expect_simple_value()
{
    if(value_type == 1)
    {
        return v_int;
    }
    return nullopt;
}

template<typename... args>
optional<tuple<args...>> my_container::expect_tuple_value()
{
    if(v_list.size() == 0)
    {
        return nullopt;
    }
    for(const auto i: v_list)
    {
        if(!i)
        {
            return nullopt;
        }
    }
    auto the_tuple_size = sizeof...(args);
    if(v_list.size() != the_tuple_size)
    {
        return nullopt;
    }
    return get_tuple_value_from_vector<args...>(v_list, index_sequence_for<args...>{});
}
template <typename T>
optional<T> my_container::expect_value()
{
    if(is_tuple<T>::value)
    {
        return expect_tuple_value<T>();
    }
    else
    {
        return expect_simple_value<T>();
    }
}

int main()
{
    my_container test_value;
    test_value.value_type = 1;
    test_value.v_int = 1;
    auto result = test_value.expect_value<tuple<int, int>>();
    if(result)
    {
        return 0;
    }
    else
    {
        return 1;
    }
}

the heart of the problem is the line return expect_tuple_value<T>(); 问题的核心是行return expect_tuple_value<T>(); When logic goes there, the T should be tuple<args...> , but what I want is return return expect_tuple_value<args...>() . 当逻辑进入那里时,T应该是tuple<args...> ,但我想要的是return expect_tuple_value<args...>()

What about using template argument deduction and overload resolution through partial ordering of function template: 如何通过函数模板的部分排序来使用模板参数推导和重载解析:

class my_container
{

public:
    template<class T> optional<T> expect_value_simple();

    template<class...Args> optional<tuple<Args...>> expect_value_tuple();


private:
    template<class T> struct deduce_type{};

    template<typename T> 
    auto expect_value_dispatching(deduce_type<T>){
       return expect_value_simple<T>();
       }
    template<typename...Args>
    auto expect_value_dispatching(deduce_type<tuple<Args...>>){
       return expect_value_tuple<Args...>();
       }
public:     
    template<typename T> 
    auto expect_value(){
        return expect_value_dispatching(deduce_type<T>{});
        }
};

( Demo ) 演示

The if before the line in question should be a constexpr if . 有问题的行之前的if应该是constexpr if

Unpacking of types is annoying to do without using a class helper. 在不使用类助手的情况下解压缩类型很烦人。 I can do it with some fancy lambda action tho. 我可以用一些奇特的 lambda动作来做到这一点。

template<class T>
struct tag_t{using type=T;};
template<class Tag>
using type=typename Tag::type;

template<class Tuple>
struct unpack_tuple;
template<class...Ts>
struct unpack_tuple<std::tuple<Ts...>> {
  template<class F>
  decltype(auto) operator()(F&& f)const {
    return std::forward<F>(f)( tag_t<Ts>{}... );
  }
};
#define TYPE_FROM(...) \
  type< std::decay_t<decltype(__VA_ARGS__)> >

then we get 然后我们得到

if constexpr(is_tuple<T>::value)
{
    return unpack_tuple<T>{}([&](auto...tags){
      return expect_tuple_value<TYPE_FROM(tags)...>();
    });
}
else
{
    return expect_simple_value<T>();
}

and done. 并做了。

The core issue here is that you need to do argument deduction at least once to go back from a type to its variadic parameters. 这里的核心问题是你需要至少进行一次参数推导才能从一个类型返回到它的可变参数。 To do that, you must pass some instance of such a variadically-templated type to a function - but it does not have to be the original one. 要做到这一点,你必须将这种变量模板类型的一些实例传递给一个函数 - 但它不必是原始函数。

Yakk 's solution does this via a variadic lambda that is passed instances of tag-types (one per tuple type). Yakk的解决方案是通过一个可变参数lambda来实现的,该lambda传递了标签类型的实例(每个元组类型一个)。 The advantage here is that you can use a lambda instead of an explicit intermediary function every time. 这里的优点是每次都可以使用lambda而不是显式中间函数。

Oliv 's solution uses a monostate type which we can instantiate and pass to a function for type deduction. Oliv的解决方案使用monostate类型,我们可以实例化它并传递给函数进行类型推导。 It's much cleaner but requires such an intermediary function for every use case. 它更干净,但每个用例都需要这样的中介功能。

Here is a (more or less theoretical) version combining both, using templated variadic lambdas ( C++20 , and they apparently don't even have clang support as of now): 这是一个(或多或少的理论)版本结合两者,使用模板化的可变参数lambda( C ++ 20 ,他们显然现在甚至没有clang支持 ):

template<class... Args>
struct MonostateTuple
{};

template<class... Args>
auto tupleToMonostate(std::tuple<Args...>)
{
    return MonostateTuple<Args...>{};
}

template<class T, class F>
auto unpack_tuple(F&& f)
{
    using MT = decltype(tupleToMonostate(std::declval<T>()));
    return std::forward<F>(f)(MT{});
}

/// User code

template<class Tuple>
auto foo()
{
    return unpack_tuple<Tuple>([&] <typename... Args> (MonostateTuple<Args...>) {
        return expect_tuple_value<Args...>();
    });
}

It's a bit more ugly in the lambda signature (not to mention the lack of compiler support again) but theoretically combines both advantages. 它在lambda签名中更难看(更不用说再次缺乏编译器支持),但理论上结合了两个优点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用模板类型专门化模板功能 - How to specialize template function with template types 如何通过使用可变参数模板参数来专门化元组的类模板? - How to specialize a class template for a tuple by using variadic template arguments? 如果不支持可变参数模板参数,如何为元组专门化类模板? - How to specialize a class template for a tuple when variadic template arguments are not supported? 是否可以专门针对模板化类型的模板? - Is it possible to specialize a template for templated types? 为包含typedef的类型专门化模板 - Specialize template for types that contain typedef 如何专门化/重载相等模板参数类型的函数? - How to specialize/overload a function for equal template parameter types? 如何为所有派生类型部分专门化一个类模板? - How to partially specialize a class template for all derived types? 如何分别为整数和浮点类型专门设计模板函数? - How to specialize a template function for integral and floating types respectively? 如何为所有非数组类型专门化模板? - How does one specialize a template for all non-array types? 如何针对程序相似的不同数据类型特化模板function? - How to specialize a template function for different data types in which the procedures are similar?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM