Intel C 编译器的编译非常慢,无法编译递归声明返回
Intel C++ Compiler is extremely slow to compile recursive decltype returns
我正在编写一个由任意数量的char
标签参数参数的表达式的模板。
给定参数列表,出厂功能返回不同类型的表达式,具体取决于是否有两个类型的参数或它们是唯一的。
一个具体的示例:假设A
是一个可标记的对象,其operator()
重载以产生?Expression<...>
。令a, b, ...
称为标签LabelName<'a'>, LabelName<'b'>, ...
。然后A(a,b,c,d)
将产生UniqueExpression<'a','b','c','d'>
,而A(a,c,b,c)
代替RepeatedExpression<'a','c','b','c'>
。
为了实现这一目标,我必须使用auto
和decltype
定义?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和英特尔编译器正确编译。现在,我知道编译器将花费更多时间来执行递归模板扣除,因为我将使用我使用的标签数量。
在我的计算机上,如果build_expression
用一个参数调用,则GCC 4.7.1的平均编译约为0.26秒。对于五个参数,编译时间缩放到约0.29秒,而十个参数的0.62秒。这都是完全合理的。
英特尔编译器的故事完全不同。ICPC 13.0.1在0.35秒内编译单题代码,并且编译时间最多可用于四个参数。在五个论点时,编译时间长达12秒,在六个论点上,它的射击超过了9600秒(即2小时40分钟)。不用说,我没有等待足够长的时间来找出编译七词版本需要多长时间。
立即想到两个问题:
Intel编译器是否特别为编译递归
decltype
?
来缓慢是否有任何方法可以重写此代码以可能与编译器更友好的方式实现相同的效果?
这是一个刺伤。我没有对每个元素进行成对比较,而是对类型列表进行排序,然后使用脑死亡的唯一算法来查看是否有重复。
我实施了合并类型的合并,因为它很有趣。在合理数量的参数上可能会更好地工作。请注意,一些工作将使我们能够在长列表上进行合并,并专门针对短列表中的气泡(甚至插入)。我不愿意编写模板QuickSort。
这给了我一个编译时间布尔值,说明列表中是否有重复项。然后,我可以使用enable_if选择我要使用的超载。
请注意,您的解决方案涉及n^2层模板递归层,在每个阶段,返回类型都需要评估1步简单类的类型,然后返回的类型也需要相同!如果英特尔编译器的备忘录失败,您正在谈论指数的工作量。
我与一些助手一起增加了您的一些课程。我从std::integral_constant
继承了您的LabelName
S继承,因此我可以轻松地编译时间访问其价值。这使得排序代码变得更加容易。我还从重复和唯一的返回值中暴露了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"作为整数变量。在做不平凡的事情时,给您的打字名称有意义的名字。
这是如何在英特尔上编译的?
- 包含模板文件的递归会导致编译失败
- 使用 SFINAE 作为模板参数的编译时递归
- 为什么我的递归可变参数模板无法编译?
- 递归应用 C++20 范围适配器会导致编译时无限循环
- 我试图用c++编写递归fibonacci序列,但当我编译时,我遇到了一个错误
- 为什么递归 constexpr 模板值无法编译?
- 具有编译问题的简单(递归)可变参数模板"accumulate_for"函数
- 为什么使用递归lambda时会遇到编译错误
- 范围的递归函数(从范围 v3 开始)导致编译发散:为什么
- 如何制作递归编译时间变异结构模板
- 使用C 模板函数编译时间递归
- Boost.Spirit X3 编译时间因递归规则而爆炸
- 提升分配器无法在递归上下文中编译
- Intel C 编译器的编译非常慢,无法编译递归声明返回
- sudoku递归回溯,未提早编译
- 编译时间递归函数以计算两个整数的下一个功能
- 预编译标头是递归的
- 使用选择算法编译时递归排序
- 递归提升::变量类型不能用"-std=c++11 -stdlib=libc++"编译
- 编译递归模板以调用静态成员函数时类型不完整