英特尔C ++编译器编译递归decltype返回速度非常慢

我正在为由任意数量的char标签进行参数化的表达式编写模板。

给定一个参数列表,一个工厂函数根据是否有两个相同类型的参数或它们是否唯一,返回不同类型的表达式。

一个具体的例子:假设A是一个“labelable”对象,其operator()重载以产生一个?Expression<...> 。 设a, b, ...被声明为标签LabelName<'a'>, LabelName<'b'>, ... 然后A(a,b,c,d)产生一个UniqueExpression<'a','b','c','d'> A(a,b,c,d) ,而A(a,c,b,c)会产生一个RepeatedExpression<'a','c','b','c'>代替。

为了达到这个目的,我必须使用autodecltype来定义?Expression的工厂函数。 此外, decltype必须级联到另一个decltype直到元程序通过参数递归完成,并且返回类型最终决定。 作为一个例子,我已经为工厂方法隔离了一个相当简单的代码。

template <typename... T> struct TypeList { };
template <char C> struct LabelName { };

template <typename... T> class UniqueExpression
{
    // Contains implementation details in actual code
};

template <typename... T> class RepeatedExpression
{
    // Contains implementation details in actual code
};

class ExpressionFactory {
private:
    template <char _C, typename... T, typename... _T>
    static UniqueExpression<T...>
    _do_build(TypeList<T...>,
              TypeList<LabelName<_C>>,
              TypeList<>,
              TypeList<_T...>)
    {
        return UniqueExpression<T...> ();
    }

    template <char _C, typename... T, typename... _T1, typename... _T2, typename... _T3>
    static RepeatedExpression<T...>
    _do_build(TypeList<T...>,
              TypeList<LabelName<_C>, _T1...>, 
              TypeList<LabelName<_C>, _T2...>,
              TypeList<_T3...>)

    {
        return RepeatedExpression<T...> ();
    }

    template <char _C1, char _C2, typename... T, typename... _T1, typename... _T2, typename... _T3>
    static auto
    _do_build(TypeList<T...>,
              TypeList<LabelName<_C1>, _T1...>, 
              TypeList<LabelName<_C2>, _T2...>,
              TypeList<_T3...>)
    -> decltype(_do_build(TypeList<T...>(),
                          TypeList<LabelName<_C1>, _T1...>(),
                          TypeList<_T2...>(),
                          TypeList<_T3..., LabelName<_C2>>()))
    {
        return _do_build(TypeList<T...>(),
                         TypeList<LabelName<_C1>, _T1...>(),
                         TypeList<_T2...>(),
                         TypeList<_T3..., LabelName<_C2>>());
    }

    template <char _C1, char _C2, typename... T, typename... _T1, typename... _T2>
    static auto
    _do_build(TypeList<T...>,
              TypeList<LabelName<_C1>, LabelName<_C2>, _T1...>, 
              TypeList<>,
              TypeList<LabelName<_C2>, _T2...>)
    -> decltype(_do_build(TypeList<T...>(),
                          TypeList<LabelName<_C2>, _T1...>(),
                          TypeList<_T2...>(),
                          TypeList<>()))
    {
        return _do_build(TypeList<T...>(),
                         TypeList<LabelName<_C2>, _T1...>(),
                         TypeList<_T2...>(),
                         TypeList<>());
    }

public:
    template <char C, typename... T>
    static auto
    build_expression(LabelName<C>, T...)
    -> decltype(_do_build(TypeList<LabelName<C>, T...>(),
                          TypeList<LabelName<C>, T...>(),
                          TypeList<T...>(),
                          TypeList<>()))
    {
        return _do_build(TypeList<LabelName<C>, T...>(),
                         TypeList<LabelName<C>, T...>(),
                         TypeList<T...>(),
                         TypeList<>());
    }
};

工厂可以像这样在程序中调用:(在实际的程序中有另一个带有重载operator()类,它调用工厂)

int main()
{
    LabelName<'a'> a;
    LabelName<'b'> b;
    ...
    LabelName<'j'> j;

    auto expr = ExpressionFactory::build_expression(a,b,c,d,e,f,g,h,i,j);

    // Perhaps do some cool stuff with expr

    return 0;
}

上述代码按预期工作,并由GCC和Intel编译器正确编译。 现在,我知道编译器需要更多时间来执行递归模板推演,因为我调整了使用的标签数量。

在我的电脑上,如果用一个参数调用build_expression ,那么GCC 4.7.1平均需要大约0.26秒的时间进行编译。 对于五个参数,编译时间可以扩展到大约0.29秒,对于十个参数,编译时间可以扩展到0.62秒。 这完全合理。

这个故事与英特尔编译器完全不同。 ICPC 13.0.1在0.35秒内编译单参数代码,编译时间对于最多四个参数保持不变。 在五个参数中,编译时间长达12秒,而在六个参数上,它在9600秒以上(即超过2小时40分钟)上升。 不用说,我没有等待足够长的时间来找出编译七个参数版本需要多长时间。


马上就会想到两个问题:

  • 特别是英特尔编译器是否知道编译递归decltype速度很慢?

  • 有什么方法可以重写这段代码,以便可能对编译器更友好的方式达到相同的效果?


  • 这是一个刺伤它。 我不是对每个元素进行两两比较,而是对类型列表进行排序,然后使用大脑死亡的独特算法来查看是否有任何重复。

    我在类型上实现了合并排序,因为它很有趣。 可能是一种天真的泡泡排序会在合理数量的参数上更好地工作。 请注意,一些工作将允许我们在长列表上进行合并排序,并专门用于短列表中的冒泡排序(甚至插入排序)。 我不想写一个模板快速排序。

    这给了我一个编译时间布尔值,说明列表中是否有重复项。 然后我可以使用enable_if来选择我要使用的超载。

    请注意,您的解决方案涉及n ^ 2层模板递归,在每个阶段返回类型需要评估1个步骤较简单的类的类型,然后返回的类型也需要相同! 如果英特尔编译器记忆失败,则说明指数量的工作。

    我用一些助手增加了一些你的类。 我做你的LabelName从s继承std::integral_constant ,所以我要自己的价值容易编译时访问。 这使得排序代码更容易一些。 我还暴露了重复和唯一返回值的enum ,所以我可以对结果进行简单的printf调试。

    这项工作大部分都是编写合并排序 - 是否有我们可以使用的标准编译时类型排序?

    #include <type_traits>
    #include <iostream>
    
    template <typename... T> struct TypeList { };
    
    // NOTE THIS CHANGE:
    template <char C> struct LabelName:std::integral_constant<char, C> {};
    
    template <typename... T> class UniqueExpression
    {
        // Contains implementation details in actual code
    public:
      enum { is_unique = true };
    };
    
    template <typename... T> class RepeatedExpression
    {
        // Contains implementation details in actual code
    public:
      enum { is_unique = false };
    };
    
    // A compile time merge sort for types
    // Split takes a TypeList<>, and sticks the even
    // index types into Left and odd into Right
    template<typename T>
    struct Split;
    template<>
    struct Split<TypeList<>>
    {
      typedef TypeList<> Left;
      typedef TypeList<> Right;
    };
    template<typename T>
    struct Split<TypeList<T>>
    {
      typedef TypeList<T> Left;
      typedef TypeList<> Right;
    };
    
    // Prepends First into the TypeList List.
    template<typename First, typename List>
    struct Prepend;
    template<typename First, typename... ListContents>
    struct Prepend<First,TypeList<ListContents...>>
    {
      typedef TypeList<First, ListContents...> type;
    };
    
    template<typename First, typename Second, typename... Tail>
    struct Split<TypeList<First, Second, Tail...>>
    {
      typedef typename Prepend< First, typename Split<TypeList<Tail...>>::Left>::type Left;
      typedef typename Prepend< Second, typename Split<TypeList<Tail...>>::Right>::type Right;
    };
    
    // Merges the sorted TypeList<>s Left and Right to the end of TypeList<> MergeList
    template< typename Left, typename Right, typename MergedList=TypeList<> >
    struct Merge;
    template<typename MergedList>
    struct Merge< TypeList<>, TypeList<>, MergedList >
    {
      typedef MergedList type;
    };
    template<typename L1, typename... Left, typename... Merged>
    struct Merge< TypeList<L1, Left...>, TypeList<>, TypeList<Merged... >>
    {
      typedef TypeList<Merged..., L1, Left...> type;
    };
    template<typename R1, typename... Right, typename... Merged>
    struct Merge< TypeList<>, TypeList<R1, Right...>, TypeList<Merged...> >
    {
      typedef TypeList<Merged..., R1, Right...> type;
    };
    template<typename L1, typename... Left, typename R1, typename... Right, typename... Merged>
    struct Merge< TypeList<L1, Left...>, TypeList<R1, Right...>, TypeList<Merged...>>
    {
      template<bool LeftIsSmaller, typename LeftList, typename RightList, typename MergedList>
      struct MergeHelper;
    
      template<typename FirstLeft, typename... LeftTail, typename FirstRight, typename... RightTail, typename... MergedElements>
      struct MergeHelper< true, TypeList<FirstLeft, LeftTail...>, TypeList<FirstRight, RightTail...>, TypeList<MergedElements...> >
      {
        typedef typename Merge< TypeList<LeftTail...>, TypeList< FirstRight, RightTail... >, TypeList< MergedElements..., FirstLeft > >::type type;
      };
      template<typename FirstLeft, typename... LeftTail, typename FirstRight, typename... RightTail, typename... MergedElements>
      struct MergeHelper< false, TypeList<FirstLeft, LeftTail...>, TypeList<FirstRight, RightTail...>, TypeList<MergedElements...> >
      {
        typedef typename Merge< TypeList<FirstLeft, LeftTail...>, TypeList<RightTail... >, TypeList< MergedElements..., FirstRight > >::type type;
      };
    
      typedef typename MergeHelper< (L1::value < R1::value), TypeList<L1, Left...>, TypeList<R1, Right...>, TypeList<Merged...> >::type type;
    };
    
    // Takes a TypeList<T...> and sorts it via a merge sort:
    template<typename List>
    struct MergeSort;
    template<>
    struct MergeSort<TypeList<>>
    {
      typedef TypeList<> type;
    };
    template<typename T>
    struct MergeSort<TypeList<T>>
    {
      typedef TypeList<T> type;
    };
    template<typename First, typename Second, typename... T>
    struct MergeSort<TypeList<First, Second, T...>>
    {
      typedef Split<TypeList<First, Second, T...>> InitialSplit;
      typedef typename MergeSort< typename InitialSplit::Left >::type Left;
      typedef typename MergeSort< typename InitialSplit::Right >::type Right;
      typedef typename Merge< Left, Right >::type type;
    };
    
    // Sorts a TypeList<T..>:
    template<typename List>
    struct Sort: MergeSort<List> {};
    
    // Checks sorted TypeList<T...> SortedList for adjacent duplicate types
    // return value is in value
    template<typename SortedList>
    struct Unique;
    
    template<> struct Unique< TypeList<> >:std::true_type {};
    template<typename T> struct Unique< TypeList<T> >:std::true_type {};
    
    template<typename First, typename Second, typename... Tail>
    struct Unique< TypeList< First, Second, Tail... > >
    {
      enum
      {
        value = (!std::is_same<First, Second>::value) &&
          Unique< TypeList<Second, Tail...> >::value
      };
    };
    
    // value is true iff there is a repeated type in Types...
    template<typename... Types>
    struct RepeatedType
    {
      typedef TypeList<Types...> MyListOfTypes;
    
      typedef typename Sort< MyListOfTypes >::type MyListOfTypesSorted;
      enum
      {
        value = !Unique< MyListOfTypesSorted >::value
      };
    };
    
    // A struct that creates an rvalue trivial constructed type
    // of any type requested.
    struct ProduceRequestedType
    {
      template<typename Result>
      operator Result() { return Result(); };
    };
    
    struct ExpressionFactory {
      template<typename... T>
      typename std::enable_if<
        !RepeatedType<T...>::value,
        UniqueExpression<T...>
      >::type
      build_expression(T...) const
      {
        return ProduceRequestedType();
      };
      template<typename... T>
      typename std::enable_if<
        RepeatedType<T...>::value,
        RepeatedExpression<T...>
      >::type
      build_expression(T...) const
      {
        return ProduceRequestedType();
      };
    };
    
    // Simple testing code for above:
    int main()
    {
      auto foo1 = ExpressionFactory().build_expression( LabelName<'a'>(), LabelName<'b'>(), LabelName<'a'>() );
      typedef decltype(foo1) foo1Type;
      if (foo1Type::is_unique)
        std::cout << "foo1 is uniquen";
      else
        std::cout << "foo1 is repeatedn";
    
      auto foo2 = ExpressionFactory().build_expression( LabelName<'q'>(), LabelName<'a'>(), LabelName<'b'>(), LabelName<'d'>(), LabelName<'t'>(), LabelName<'z'>() );
      typedef decltype(foo2) foo2Type;
      if (foo2Type::is_unique)
        std::cout << "foo2 is uniquen";
      else
        std::cout << "foo2 is repeatedn";
    }
    

    另外,我想添加批评您的代码:模板编程是编程 - 您的类型名称相当于将“i1”通过“i9”用于函数中的整数变量。 在做一些不重要的事情时给你的类型名称有意义的名字。

    这在英特尔如何编译?

    链接地址: http://www.djcxy.com/p/11399.html

    上一篇: Intel C++ Compiler is extremely slow to compile recursive decltype returns

    下一篇: Tracing from an effect back to its cause in a large Python codebase