枚举元组类型的最佳方法?

时间:2020-01-02 02:01:48

标签: c++

正如标题所述,我正在寻找枚举元组类型的最佳方法。 所以我的第一次尝试是下面的代码,它是对stackoverflow的另一个答案的改编,唯一的变化是包装在另一个类上,因此不需要将元组类型作为模板参数传递:

#include <tuple>
using namespace std;
using uInt = size_t;

template<typename... ARGS>
class ECS_Data
{
private:
    tuple<ARGS...> data;

private:
    //TYPE INDEXING
    template<typename T, typename Types>
    struct Internal_Type_Index;

    template<typename T>
    struct Type_Index {
        static constexpr uInt value = Internal_Type_Index<T, tuple<ARGS...>>::value;
    };

    template<typename T, typename U, typename... Types>
    struct Internal_Type_Index<T, tuple<U, Types...>> {
        static constexpr uInt value = 1 + Internal_Type_Index<T, tuple<Types...>>::value;
    };

    template<typename T, typename... Types>
    struct Internal_Type_Index<T, tuple<T, Types...>> {
        static constexpr uInt value = 0;
    };

public:
    template<typename T>
    static constexpr uInt Type_Index_v = Type_Index<T>::value;

};

int main()
{
  ECS_Data<int,float,double,long long,char> ecs_data;
  return ecs_data.Type_Index_v<char>; //return 4
}

“问题”是,对于具有50个类型的元组来说,它实例化了1350个结构,每个结构都带有一个静态变量。 例如,对于tuple<int,float,double>: 用int调用将实例化1个结构Internal_Type_Index<int, tuple<int, Types...>>并停止,因为立即发现了int。 用float调用将实例化2个结构Internal_Type_Index<float, tuple<int, Types...>>,然后Internal_Type_Index<float, tuple<float, Types...>>然后停止,因为找到了float,以此类推...导致3 + 2 + 1实例化(假设为{{1 }}被所有类型调用。 那么Type_Index_v实例化对吧? N + (N+N^2)/2 NType_Index (N+N^2)/2部分专业化(全部1350中都有一个静态变量)。

我的第二个解决方法是:

Internal_Type_Index

还是以50个类型的元组为例,这次我们有: #include <tuple> #include <utility> using namespace std; using uInt = size_t; template<typename... ARGS> class ECS_Data { private: tuple<ARGS...> data; template<typename T> inline static uInt _index = 0; public: ECS_Data() { init_index(std::make_index_sequence<sizeof...(ARGS)>()); } template<typename T> uInt index()const { return _index<T>; } private: template<size_t... N> void init_index(std::index_sequence<N...>) { (..., (_index<ARGS> = N)); } }; int main() { ECS_Data<int,float,double,char> ecs_data; return ecs_data.index<char>(); } 的2 + N个实例 来自make_index_sequence的50个静态模板变量 _index的50个成员函数实例化 从数字上看,这似乎更好,但是现在是运行时,因为像上面的代码中那样,用折叠表达式初始化index<T>() constexpr时,我看不到一种方法。

所以我的问题是: 1)您是否看到一种改进上面代码的方法? 2)考虑到所有因素(例如编译器优化魔术),最终哪个版本更好? 3)您可以建议一个更好的版本? 编辑:原谅如果很难阅读,那么stackoverflow上的文本编辑器完全忽略了我的换行符。

2 个答案:

答案 0 :(得分:2)

我会做的:

template <typename T, typename Tuple, std::size_t ... Is>
constexpr std::size_t tuple_index_impl(std::index_sequence<Is...>)
{
    // You might adapt here to handle duplicate differently
    return std::max({ std::is_same<T, std::tuple_element_t<Is, Tuple>>::value * (Is + 1)... });
}

template <typename T, typename Tuple>
constexpr std::size_t tuple_index()
{
   return tuple_index_impl<T, Tuple>(std::make_index_sequence<std::tuple_size<Tuple>::value>());
}

Demo

通过类型+ std::index_sequence对这两个方法进行一次实例化(这可能由编译器以1种唯一的实例化方式神奇地完成)。

答案 1 :(得分:1)

我只会在3点开枪。我的镜头看起来像这样:

import numpy as np
from scipy.optimize import curve_fit

concentration = np.array(
    [
        [0.6, 0.59642147, 0.5859375, 0.56603774, 0.53003534, 0.41899441],
        [0.06, 0.11928429, 0.29296875, 0.62264151, 1.21908127, 3.05865922],
    ]
)

protein = concentration[0, :]
ligand = concentration[1, :]

titration_data = np.array(
    [
        [0, 0, 0.29888413, 0.45540198, 0.72436899, 1],
        [0, 0, 0.11930228, 0.35815982, 0.59396978, 1],
        [0, 0, 0.30214337, 0.46685577, 0.79007708, 1],
        [0, 0, 0.27204954, 0.56702549, 0.84013344, 1],
        [0, 0, 0.266836, 0.43993175, 0.74044123, 1],
        [0, 0, 0.28179148, 0.42406587, 0.77048624, 1],
        [0, 0, 0.2281092, 0.50336244, 0.79089151, 0.87029517],
        [0, 0, 0.18317694, 0.55478412, 0.78448465, 1],
    ]
)

def fun(_, kd):
    a = protein
    b = protein + ligand
    c = ligand
    return np.array((b + kd - np.sqrt(((b + kd) ** 2) - 4 * a * c)) / (2 * a))

def glob_fun(_, kd):
    return np.tile(fun(_, kd), len(titration_data))

x = ligand
y = titration_data
popt, pcov = curve_fit(glob_fun, x, y.ravel())

可以像

那样使用
let chai = require("chai").use(require("chai-as-promised"));
import { defineSupportCode } from 'cucumber';
import {browser, element, by, ElementFinder, $, $$ , until } from 'protractor' ;
const expect = chai.expect;
import { HomePage } from '../page-objects/pm360-home-page';
import { LoginPage } from '../page-objects/pm360-login-page';

   var pm360_homepage  = new HomePage();
   //var pm360_loginpage = new LoginPage();

  defineSupportCode(({Given,Then }) => {
  Given('I login into pm360 page with a valid authentication {string} and {string}',   
  async function givenauth(username: string, password: string): Promise<void>{
    pm360_homepage.OpenBrowser('https://pm360-qa.parkmobile.io/'); 
    await pm360_homepage.usernameField.sendKeys('.....');
    await pm360_homepage.passwordField.sendKeys('......');
    //browser.actions().sendKeys(protractor.Button.MIDDLE).click();
    pm360_homepage.ClickLogIn(); 
    //pm360_homepage.logInBtn.click().then(()=> {"looged In"});
    //browser.touchActions().tap(pm360_homepage.logInBtn).perform().then(()=> {"logged In"});
    browser.ignoreSynchronization = true;
});
   Given('I navigate through manage policies',
   async function givenmanaging():Promise<void>{
    browser.ignoreSynchronization = true;
    //browser.wait(until.elementsLocated(pm360_homepage.managePoliciesBtn));
    await pm360_homepage.managePoliciesBtn.click();
    //browser.waitForAngularEnabled(true);

实时:http://coliru.stacked-crooked.com/a/8ea39202298f2ddc

这里的键是template <typename Tuple, typename Needle, std::size_t... I> constexpr std::size_t tuple_index_impl(std::index_sequence<I...>) { // don't use std::disjunction_v here as it will return bool constexpr std::size_t idx = std::disjunction< // need I+1 to prevent a falsy result on index 0 std::integral_constant<std::size_t, (I+1) * std::is_same_v<std::tuple_element_t<I, Tuple>, Needle>>..., // fallthrough case std::integral_constant<std::size_t, 0> >::value; static_assert(idx != 0, "type not found in tuple"); return idx - 1; } template <typename Tuple, typename Needle> constexpr std::size_t tuple_index() { return tuple_index_impl<Tuple, Needle>( std::make_index_sequence<std::tuple_size_v<Tuple>>{}); } ,在找到值之后,不需要实例化任何模板参数。这也适用于任何类似元组的类型(实现using T = std::tuple<int, long long, double, char, double>; //std::cout << tuple_index<T, float>(); //ERROR: type not found in tuple std::cout << tuple_index<T, double>(); // prints "2", the first one std::cout << tuple_index<T, char>(); // prints "3" std::disjunction接口的事物)。

由于这显然是tuple_element /模板的全部魔力,因此唯一需要付出的代价就是在编译时。我猜想这在这方面的性能如何取决于编译器tuple_size实现的效率,但是我没有做任何分析。