在运行时期间基于底层元组类型生成元素

时间:2016-06-15 16:04:51

标签: c++ c++11 tuples

如何在编译时推断出类型或对元素?我需要它来根据参数类型做出正确的实例(例如对于Integer_random_generator,那些可能是long,int,unsigned int等,对于real_random_generator double,float和其他浮点)。我需要制作具有特定界限的发电机,如您在注释掉的第63-77行中所见。

#ifndef OPTIMALIZATION_HPP
#define OPTIMALIZATION_HPP

    #include<utility>
    #include<random>
    #include<experimental/random>
    #include<functional>
    #include<experimental/functional>
    #include<experimental/tuple>
    #include<algorithm>
    #include<type_traits>
    #include<iostream>

    #include"tuple_for_each.hpp"

    //ZNAJDZ/ZROB INDEKSOWANY DOSTEP DO TUPLI W CZASIE RUN-TIME'U
    namespace numerics{
        template<
            std::size_t population_size, std::size_t generations,
            typename Func,
            typename Compare, //GREATER, LESS, TYPE RETURNED BY FUNCTION
            typename Generator=std::default_random_engine,
            template<typename>
                typename RealDistribution=std::uniform_real_distribution,
            template<typename>
                typename IntegerDistribution=std::uniform_int_distribution,
            typename ...Ts
        >
        auto optimize(
                const Func& function, const Compare& comp,
                const std::pair<Ts,Ts>&... range
        ){

            std::size_t range_argument_count=sizeof...(range);
            static_assert(range_argument_count>2,
                    "Function needs at least two range arguments"
            );

            //RANDOM NUMBER GENERATORS
            auto real_random_generator=[&](const std::pair<auto,auto> range){
                std::cout << "DOUBLE" << std::endl;
                return std::bind(
                        RealDistribution<long double>(range.first,range.second),
                        //RealDistribution<decltype(range.first)>(range.first,range.second);
                        //HOW TO DEDUCE TYPE OF DISTRIBUTION FROM PAIR DURING COMPILE-TIME???
                        Generator()
                );
            };

            auto integer_random_generator=[&](const std::pair<auto,auto>& range){
            std::cout << "INTEGER" << std::endl;
                return std::bind(
                        IntegerDistribution<long long>(range.first,range.second),
                        //IntegerDistribution<decltype(range.first)>(range.first,range.second);
                        //HOW TO DEDUCE TYPE OF DISTRIBUTION FROM PAIR DURING COMPILE-TIME???
                        Generator()
                );
            };
            std::cout << integer_random_generator(std::get<0>(std::make_tuple(range...)))() << std::endl;
            std::cout << real_random_generator(std::get<1>(std::make_tuple(range...)))()<<std::endl;
            std::cout << integer_random_generator(std::get<2>(std::make_tuple(range...)))()<<std::endl;

            //GENERATORS DEPENDING ON TYPE, USED THROUGH WHOLE PROGRAM
            /*std::tuple<> generators;
            numerics::for_each(std::make_tuple(range...), [&](std::pair<auto,auto>& x){ //FOR_EACH SPRAWDZENIA
                    try{
                        generators=std::tuple_cat(
                                generators,
                                std::make_tuple(integer_random_generator(x.first)));
                    }
                    catch(...){
                        generators=std::tuple_cat(
                                generators,
                                std::make_tuple(real_random_generator(x.first)));
                    }
                }
            );*/
            return "pls work";
        }
    }
    #endif  

测试用例:

#include<utility>
#include<iostream>
#include"optimize.hpp"

class Function{
    public:
        Function()=default;
        double operator()(int x, double y, long z)const{
            return (std::exp(x+1.25)*std::pow(y,z))/std::exp((x*y)/z);
        }
};

int main(){
    Function f{};
    auto comp=std::less<double>();
    auto x=numerics::optimize<100, 200>(
            f, comp,
            std::make_pair(-21, 37),
            std::make_pair(14.88, 88.41),
            std::make_pair(-13, 37)
    );
    std::cout << x << std::endl;

}

1 个答案:

答案 0 :(得分:2)

编写辅助函数以确定是生成实数还是整数生成器。在这种情况下,它将基于范围中第一个参数的类型。我将留给您确定如何检查第二个参数。 (我还没有测试过这段代码,但我确信这个想法很有效。)

template <class Range>
auto get_distribution(Range range, std::true_type)
{
    return real_random_generator(range);
}

template <class Range>
auto get_distribution(Range range, std::false_type)
{
    return integer_random_generator(range);
}

只需使用包扩展语法在每个范围内调用辅助函数

auto generators = std::make_tuple(get_distribution(ranges, 
                      std::is_floating_point<decltype(ranges.first)>{})...);

std::is_floating_point决定了为每个范围调用哪个重载。

如果您喜欢棘手但更简洁的代码,可以尝试一下:

auto fs = std::make_tuple(integer_random_generator, real_random_generator);
auto generator = std::make_tuple(std::get<std::is_floating_point<decltype(ranges.first)>::value>(fs)(ranges)...);

构造生成器生成lambdas的元组(如果它们不是对象,这将不起作用)并使用条件作为元组的索引并立即调用它。我不主张使用它,但我想我会分享它。