簡體   English   中英

關於MSVC和g ++如何處理C ++模板代碼之間的差異

[英]Regarding differences between how MSVC and g++ treat C++ template code

我偶然發現了ACCU的這段代碼( http://accu.org/index.php/journals/1916 ),並且有興趣在C ++中使用CRTP來實現一個有趣的項目。 作者給出的代碼如下:

namespace aop
{

template <class A>
class NullAspect
{};

template <template <template <class> class> class Base>
struct Decorate
{
private:
    struct None {};

    template <template <class> class ... Aspects>
    struct Apply;

    template <template <class> class T>
    struct Apply<T>
    {
        template <class E>
        using Type = T<E>;
    };

    template<template < class > class A1, template < class > class ... Aspects>
    struct Apply<A1, Aspects...>
    {
        template <class T>
        using Type = A1<typename Apply<Aspects...>::template Type<T>>; // the errors point to this line and the 'Type' refers to the 'template Type<T>'
    };

public:
    template<template <class> class ... Aspects>
    struct with
    {
        template <class T>
        using AspectsCombination = typename Apply<Aspects...>::template Type<T>;

        typedef AspectsCombination<Base<AspectsCombination>> Type;
    };
};
}

我嘗試在Microsoft VS2015中編譯它,它給了我以下一組錯誤:

Error   C2146   syntax error: missing '>' before identifier 'Type'  
Error   C2947   expecting '>' to terminate template-argument-list, found '<'    
Error   C2061   syntax error: identifier 'T'    
Error   C2238   unexpected token(s) preceding ';'   
Error   C1201   unable to continue after syntax error in class template definition  
Error   C2143   syntax error: missing ';' before '}'    
Error   C2238   unexpected token(s) preceding ';'   

我使用相同的代碼,檢查語法並用g ++編譯它並編譯好。 我應該注意的兩個編譯器之間是否存在差異? 這會使cl.exe產生這些錯誤的問題是什么? 它們是由於cl.exe如何解析任何基於模板的代碼? 要使此代碼在msvc上運行需要進行哪些更改?

編輯:

以下是作者提供的test.cpp的完整代碼,以幫助您更清晰地了解情況:

#include <iostream>
#include <cmath>
#include "aop.h"

//#define INHERITING_CTORS  as of g++ 6.4.3, inheriting ctors was not implemented

template <typename _UnderlyingType>
struct Number
{
    template <template <class> class A = aop::NullAspect>
    class Type
    {
    public:
        typedef _UnderlyingType UnderlyingType;
        typedef A<Number::Type<A>> FullType;

        Type(UnderlyingType n)
            : n(n)
        {}

        friend std::ostream& operator<<(std::ostream& out, const Type& number)
        {
            return out << number.n;
        }
    protected:
        UnderlyingType n;
    };
};

template <class A>
class ArithmeticAspect: public A
{
public:
    typedef typename A::FullType FullType;

#ifdef INHERITING_CTORS
    using A::A;
#else
    ArithmeticAspect(typename A::UnderlyingType n)
        : A(n)
    {}

    ArithmeticAspect(const A& a)
        : A(a)
    {}
#endif

    FullType operator+(const FullType& other) const
    {
        FullType tmp(*this);
        return tmp += other;
    }

    FullType operator-(const FullType& other) const
    {
        FullType tmp(*this);
        return tmp -= other;
    }

    FullType operator+=(const FullType& other)
    {
        A::n += other.n;
        return A::n;
    }

    FullType operator-=(const FullType& other)
    {
        A::n -= other.n;
        return A::n;
    }

    // same for *, *=, /, /=
};

template <class A>
class IncrementalAspect: public A
{
public:
    typedef typename A::FullType FullType;

#ifdef INHERITING_CTORS
    using A::A;
#else
    IncrementalAspect(typename A::UnderlyingType n)
        : A(n)
    {}

    IncrementalAspect(const A& a)
        : A(a)
    {}
#endif

    FullType operator++(int)
    {
        FullType tmp(*this);
        operator++();
        return tmp;
    }

    FullType operator++()
    {
        ++A::n;
        return *this;
    }

    FullType operator--(int)
    {
        FullType tmp(*this);
        operator--();
        return tmp;
    }

    FullType operator--()
    {
        --A::n;
        return *this;
    }
};

/*
* Configurable Aspect sumExample
*/
template <unsigned int PRECISION>
struct RoundAspect
{
    template <class A>
    class Type : public A
    {
    public:
        typedef typename A::FullType FullType;

#ifdef INHERITING_CTORS
        using A::A;
#else
        Type(typename A::UnderlyingType n)
            : A(n)
        {}

        Type(const A& a)
            : A(a)
        {}
#endif

        FullType operator+(const FullType& other) const
        {
            return FullType(round(A::operator+(other).n));
        }

    private:
        static float round(float f)
        {
            const unsigned int e = std::pow(10, PRECISION);
            return float(int(f * e)) / e;
        }
    };
};

template <class A>
class LogicalAspect: public A
{
public:
    typedef typename A::FullType FullType;

#ifdef INHERITING_CTORS
    using A::A;
#else
    LogicalAspect(typename A::UnderlyingType n)
        : A(n)
    {}

    LogicalAspect(const A& a)
        : A(a)
    {}
#endif

    bool operator!() const
    {
        return !A::n;
    }

    bool operator&&(const FullType& other) const
    {
        return A::n && other.n;
    }

    bool operator||(const FullType& other) const
    {
        return A::n || other.n;
    }
};

template <class A>
class BitwiseAspect: public A
{
public:
    typedef typename A::FullType FullType;

#ifdef INHERITING_CTORS
    using A::A;
#else
    BitwiseAspect(typename A::UnderlyingType n)
        : A(n)
    {}

    BitwiseAspect(const A& a)
        : A(a)
    {}
#endif

    bool operator~() const
    {
        return ~A::n;
    }

    FullType operator&(const FullType& mask) const
    {
        return A::n & mask.n;
    }

    FullType operator|(const FullType& mask) const
    {
        return A::n | mask.n;
    }

    FullType operator<<(const FullType& bitcount) const
    {
        return A::n << bitcount.n;
    }

    FullType operator>>(const FullType& bitcount) const
    {
        return A::n >> bitcount.n;
    }

    FullType& operator>>=(const FullType& bitcount)
    {
        A::n >>= bitcount.n;
        return *static_cast<FullType*>(this);
    }
};

template <class N>
void sumExample(typename N::UnderlyingType n1, typename N::UnderlyingType n2)
{
    N a(n1);
    N b(n2);
    N c = a + b;
    std::cout << c << std::endl;
}

template <class N>
void orExample(typename N::UnderlyingType n1, typename N::UnderlyingType n2)
{
    N a(n1);
    N b(n2);
    std::cout << (a || b) << std::endl;
}

template <class N>
void bitwiseExample(typename N::UnderlyingType n1, typename N::UnderlyingType n2)
{
    N a(n1);
    N b(n2);
    std::cout << (a + ((b >>= 1) << 3)) << std::endl;
}

int main()
{

    typedef aop::Decorate<Number<unsigned int>::Type>::with<ArithmeticAspect, IncrementalAspect, LogicalAspect, BitwiseAspect>::Type IntegralNumber;
    bitwiseExample<IntegralNumber>(1, 2);
    sumExample<IntegralNumber>(1, 2);

    typedef aop::Decorate<Number<float>::Type>::with<RoundAspect<2>::Type, ArithmeticAspect, LogicalAspect>::Type FloatRoundLogicalNumber;
    orExample<FloatRoundLogicalNumber>(1, 0);

    typedef aop::Decorate<Number<int>::Type>::with<LogicalAspect>::Type IntLogicalNumber;
    orExample<IntLogicalNumber>(1, 0);

    typedef aop::Decorate<Number<float>::Type>::with<RoundAspect<2>::Type, ArithmeticAspect>::Type FloatRoundNumber;
    sumExample<FloatRoundNumber>(1.339, 1.1233);

    return 0;
}

恕我直言,它是模板化模板上的>> syndrom。 在C ++ 11之前,需要一個空格來分隔> token而不是一個>> token。

從C ++ 11開始,n4296草案在14.2中說明了模板特化的名稱[temp.names]§3:

...類似地,第一個非嵌套>>被視為兩個連續但不同的>標記,第一個作為template-argument-list的結尾並完成template-id。

看起來MSVC2015還沒有實現那部分標准(或者您可能忘記聲明源代碼的C ++版本*)

為了完整起見,在使用CLang 3.4.1進行編譯而不指定std=c++11它會顯示以下錯誤:

 error: a space is required between consecutive right angle brackets (use '> >') using Type = A1<typename Apply<Aspects...>::template Type<T>>; // the er... 

並希望在C ++ 11模式中甚至沒有警告......

(*)遺憾的是,我無法訪問VS2015,微軟在他們的C ++ 11/14/17 功能頁面中聲明了直角括號由VS2013和2015實現。所以我假設應該在項目屬性中的某處代碼級別指示。

所以在擺弄並盡可能地閱讀之后,我終於給原作者發了一封電子郵件。 Hugo Arregui先生,所有的功勞都歸功於他。

關於cl抱怨的行,修復方法如下:

template < template <class> class A1, template <class> class A2, template <class> class... Aspects>
struct Apply<A1,A2,Aspects...>
{
    template<class T>
    using Type = A1< typename Apply<A2, Aspects...>::template Type<T> >;
};

如果有人知道為什么Microsoft的編譯器要求我們在模板參數中擴展至少2個模板類並在此給出解釋,那將是很好的。 正在與作者交談,他也很驚訝。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM