gcc中的错误,或clang / MSVC中的扩展名

时间:2015-03-04 12:26:09

标签: c++ variadic-templates

以下代码段在clang和MSVS中编译,但不在gcc中编译。

template<typename T> class clone_ptr;

template<typename T, typename U, typename ...Args>
clone_ptr<T> make_cloned( Args ...args );

// note: everything not needed for example cut out, so
// this class is neither complete nor correct
template<typename T>
class clone_ptr 
{
public:
    clone_ptr() : ptr(nullptr) {}
    operator bool() { return ptr!=nullptr; }
    T* operator->() { return ptr; }
private:
    clone_ptr(T* p) : ptr(p) {}
    T* ptr;

    template<class T1,class U1, typename ...Args>
        friend clone_ptr<T1> make_cloned( Args ...args );
};

template<typename T, typename U=T, typename ...Args>
clone_ptr<T> make_cloned( Args ...args )
{
    return {new U(args...)};
}

// ----------------------------------------------

#include <string>
#include <vector>
#include <iostream>

using namespace std;

struct Base
{
    int a;
    Base( int a=0 ) : a(a) {}
    virtual string foo() { return "Base "+to_string(a); };
    virtual ~Base() {}
};

struct Sub : Base
{
    Sub( int a=0 ) : Base(a) {}
    virtual string foo() override { return "Sub "+to_string(a); };
};

string testit()
{
    std::vector< clone_ptr< Base > > vec;

    vec.push_back( make_cloned<Base>(7) );
    vec.emplace_back();
    vec.push_back( make_cloned<Base,Sub>(5) );

    string ss;
    for( auto&& a : vec )
    {
        ss += a?a->foo():"<empty>";
    }

    return ss;
}

int main()
{
    cout << testit() << endl;
}


gcc抱怨道:

error: no matching function for call to 'make_cloned(int)'
vec.push_back( make_cloned<Base>(7) );
note: candidate is:
note: template<class T, class U, class ... Args> clone_ptr<T> make_cloned(Args ...)
clone_ptr<T> make_cloned( Args ...args )
             ^
note:   template argument deduction/substitution failed:
note:   couldn't deduce template parameter 'U'
vec.push_back( make_cloned<Base>(7) );

这是gcc中的错误,是否只有解决方法 依赖于符合标准的C ++?

1 个答案:

答案 0 :(得分:2)

事实上,这似乎是一个错误。解决方法是将默认模板参数分隔为第二个函数。在clone_ptr内你有两个朋友:

template<class T1, typename ...Args>
    friend clone_ptr<T1> make_cloned( Args ...args );
template<class T1, class U1, typename ...Args>
    friend clone_ptr<T1> make_cloned( Args ...args );

,定义很简单:

template<typename T, typename ...Args>
clone_ptr<T> make_cloned( Args ...args ) { return {new T(args...)}; }
template<typename T, typename U, typename ...Args>
clone_ptr<T> make_cloned( Args ...args ) { return {new U(args...)}; }

使用gcc 4.8.3和clang 3.5进行测试。

编辑: 经过调查,我能够以两种不同的方式让您的代码使用gcc 4.8.3:

  1. 完全删除模板函数声明

    // this is not needed:
    template<typename T, typename U, typename ...Args>
    clone_ptr<T> make_cloned( Args ...args );
    
  2. 将默认模板参数定义从模板函数定义移动到声明:

    template<typename T, typename U = T, typename ...Args>
    clone_ptr<T> make_cloned( Args ...args );
    
    template<typename T, typename U, typename ...Args>
    clone_ptr<T> make_cloned( Args ...args )
    {
        return {new U(args...)};
    }
    
  3. 我仍然认为这是gcc的问题,但这样你的代码就可以了。