英特尔C ++编译器编译递归decltype返回非常慢 [英] Intel C++ Compiler is extremely slow to compile recursive decltype returns

查看:152
本文介绍了英特尔C ++编译器编译递归decltype返回非常慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为任意数量的 char 标签参数设置的表达式编写模板。



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



具体示例:假设是一个可标记对象,其运算符()重载生成?表达式; ...> 。将 a,b,... 声明为标签 LabelName<'a'>,LabelName<'b' 。然后 A(a,b,c,d)会产生一个 UniqueExpression<'a','b','c' > ,而 A(a,c,b,c)将产生 RepeatedExpression<'a'



为了实现这一点,我不得不定义?的工厂函数 auto decltype 此外, decltype 必须级联到另一个 decltype ,直到元程序通过参数完成递归,并且返回类型终于决定。作为例子,我已经为工厂方法隔离了一个相当少的代码。

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

template< typename ... T> class UniqueExpression
{
//包含实际代码中的实现细节
};

template< typename ... T> class RepeatedExpression
{
//包含实际代码中的实现细节
};

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& _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& >(),
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& >(),
TypeList<>()))
{
return _do_build(TypeList< LabelName< C>,T ...& ; LabelName< C>,T ...>(),
TypeList< T ...>(),
TypeList&
}
};

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

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

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

//也许用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


  • 有没有办法重写这个代码,以达到相同的效果,编译器?



解决方案

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



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



这给我一个编译时布尔值,说如果在列表中有重复。我可以使用enable_if来选择要使用的重载。



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



我用一些助手增加了几个类。我让你的 LabelName 继承自 std :: integral_constant ,所以我可以很容易的编译时访问他们的值。这使得排序代码更容易。我还从重复和唯一的返回值中暴露了一个枚举,所以我可以对结果做简单的 printf 调试。 / p>

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

  #include< type_traits> 
#include< iostream>

template< typename ... T> struct TypeList {};

//注意此更改:
template< char C> struct LabelName:std :: integral_constant< char,C> {};

template< typename ... T> class UniqueExpression
{
//包含实际代码中的实现细节
public:
enum {is_unique = true};
};

template< typename ... T> class RepeatedExpression
{
//包含实际代码中的实现细节
public:
enum {is_unique = false};
};

//类型的编译时合并排序
// Split接受一个TypeList<>,并将偶数
//索引类型保留为Left,奇数保持为Right
template< typename T>
struct Split;
模板<>
struct Split< TypeList<>>
{
typedef TypeList<>剩下;
typedef TypeList<>对;
};
template< typename T>
struct Split< TypeList< T>>
{
typedef TypeList< T>剩下;
typedef TypeList<>对;
};

//先进入类型列表列表。
template< typename首先,类型名列表>
struct Prepend;
template< typename首先,typename ... ListContents>
struct Prepend< First,TypeList< ListContents ...>>
{
typedef TypeList< First,ListContents ...>类型;
};

template< typename首先,typename第二,typename ...尾>
struct Split< TypeList< First,Second,Tail ...>>
{
typedef typename Prepend<首先,类型名Split< TypeList< Tail ...>> :: Left> :: type Left;
typedef typename Prepend<第二,类型名Split< TypeList< Tail ...>> :: Right> :: type Right;
};

//将经排序的TypeList<>的Left和Right合并到TypeList<> MergeList
template< typename Left,typename Right,typename MergedList = TypeList<> >
struct Merge;
template< typename MergedList>
struct Merge< TypeList<>,TypeList<>,MergedList>
{
typedef MergedList类型;
};
template< typename L1,typename ... Left,typename ... Merged>
struct Merge< TypeList< L1,Left ...>,TypeList<>,TypeList< Merged ...>>
{
typedef TypeList< Merged ...,L1,Left ...>类型;
};
template< typename R1,typename ... Right,typename ... Merged>
struct Merge< TypeList<>,TypeList< R1,Right ...>,TypeList< Merged ...> >
{
typedef TypeList< Merged ...,R1,Right ...>类型;
};
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;
};

//获取一个TypeList< T ...>并通过合并排序对它进行排序:
template< typename List>
struct MergeSort;
模板<>
struct MergeSort< TypeList<>>
{
typedef TypeList<>类型;
};
template< typename T>
struct MergeSort< TypeList< T>>
{
typedef TypeList< T>类型;
};
template< typename首先,typename第二,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;
};

//排序TypeList< T ..>:
template< typename List>
struct Sort:MergeSort< List> {};

//检查排序TypeList< T ...>用于相邻重复类型的SortedList
//返回值在值
template< typename SortedList>
struct Unique;

模板<> struct Unique< TypeList<> >:std :: true_type {};
template< typename T> struct Unique< TypeList< T> >:std :: true_type {};

template< typename首先,typename第二,typename ...尾>
struct Unique< TypeList<第一,第二,尾...> >
{
enum
{
value =(!std :: is_same< First,Second> :: value)&&
Unique< TypeList< Second,Tail ...> > :: value
};
};

//如果在Types ...中有重复的类型,值为true。
template< typename ... Types>
struct RepeatedType
{
typedef TypeList< Types ...> MyListOfTypes;

typedef typename Sort< MyListOfTypes> :: type MyListOfTypesSorted;
enum
{
value =!Unique< MyListOfTypesSorted> ::value
};
};

//一个结构体,创建一个值为任何类型请求的值的简单的构造类型
//。
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();
};
};

//上面的简单测试代码:
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 unique\\\
;
else
std :: cout<< foo1 is repeated\\\
;

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 unique \\\
;
else
std :: cout<< foo2 is repeated\\\
;
}

此外,我想添加一个对你的代码的批判:模板编程是编程 - 您的类型名称相当于在函数中使用i1到i9作为整数变量。



在英特尔上如何编译?


I'm writing a template for expressions parametrised by an arbitrary number of char labels.

Given an argument list, a factory function returns an expression of different types depending on whether there are two arguments of the same types or whether they are unique.

A concrete example: suppose that A is a "labelable" object with its operator() overloaded to produce an ?Expression<...>. Let a, b, ... be declared as labels LabelName<'a'>, LabelName<'b'>, .... Then A(a,b,c,d) would produce a UniqueExpression<'a','b','c','d'>, whereas A(a,c,b,c) would produce a RepeatedExpression<'a','c','b','c'> instead.

To achieve this, I had to define the ?Expression's factory function with auto and decltype. Moreover, the decltype has to cascade to another decltype until the metaprogram finishes recursing through the arguments and the return type is finally decided. As an illustration, I have isolated a fairly minimal code for the factory method.

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<>());
    }
};

The factory could be called in the program like so: (in the actual program there is another class with an overloaded operator() which calls the factory)

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;
}

The above code works as intended, and is correctly compiled by both GCC and the Intel compiler. Now, I understand that the compiler would take more time to perform recursive template deduction as I crank up the number of labels I use.

On my computer, if build_expression is called with one argument, then GCC 4.7.1 takes around 0.26 second to compile on average. The compile time scales up to around 0.29 second for five arguments, and to 0.62 second for ten arguments. This is all perfectly reasonable.

The story is quite different with the Intel compiler. ICPC 13.0.1 compiles the one-argument code in 0.35 second, and the compile time stays pretty much constant for up to four arguments. At five arguments the compile time goes up to 12 seconds, and at six arguments it shoots up above 9600 seconds (that is, over 2 hours and 40 minutes). Needless to say, I haven't waited long enough to find out how long it takes to compile the seven-argument version.


Two questions immediately come to mind:

  • Is the Intel compiler particularly known to be slow to compile recursive decltype?

  • Is there any way to rewrite this code to achieve the same effect in a way that is perhaps friendlier to the compiler?

解决方案

Here is a stab at it. Instead of doing pairwise comparisons of each of the elements, I sort the list of types, then use a brain-dead unique algorithm to see if there are any duplicates.

I implemented merge sort on types, because it was fun. Probably a naive bubble sort would work better on reasonable number of arguments. Note that a bit of work would allow us to do a merge sort on long lists, and specialize for bubble sorts (or even insertion sorts) on short lists. I'm not up for writing a template quicksort.

This gives me a compile time boolean that says if there are duplicates in the list. I can then use enable_if to pick which overload I'm going to use.

Note that your solution involved n^2 layers of template recursion, at each stage of which the return type requires evaluating the type of a 1 step simpler class, and then the type returned also requires the same! If the Intel compiler memoization fails, you are talking exponential amounts of work.

I augmented a few of your classes with some helpers. I made your LabelNames inherit from std::integral_constant, so I have easy compile time access to their value. This makes the sorting code a tad easier. I also exposed an enum from the repeated and unique return values so I can do simple printf debugging on the result.

Most of this work is writing the merge sort -- is there a standard compile time type sort we could use?

#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 unique\n";
  else
    std::cout << "foo1 is repeated\n";

  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 unique\n";
  else
    std::cout << "foo2 is repeated\n";
}

In addition I'd like to add a critique of your code: Template programming is programming -- your typenames are the equivalent of using "i1" through "i9" for integer variables in a function. Give your typenames meaningful names when doing something non-trivial.

How does this compile on Intel?

这篇关于英特尔C ++编译器编译递归decltype返回非常慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆