与朋友模板函数clang / msvc和enable_if的问题

时间:2014-07-01 01:48:57

标签: templates visual-c++ c++11 friend clang++

我在clang ++中遇到编译器错误。 MSVC ++很高兴。我相信我的宣言是正确的。

我的信仰不正确,我在MSVC中“幸运”吗? 是否有非#ifndef _MSC_VER ... public:方法可以在两个编译器中使用它?

我想保持构造函数私有。真正的代码稍微复杂一些。 (附加模板元编程和“完美转发”)以下是问题的提炼版本,并尽可能地隔离问题。我为朋友宣言试过了很多变化。 “看起来最好”的那个在示例中显示。

#include<type_traits>

template<typename T> class Wrap;

template<typename T, 
    typename std::enable_if<std::is_class<T>::value, T>::type* = nullptr >
Wrap<T> make_wrapper( T i )
{
    return Wrap<T>( i );
}

template<typename T>
class Wrap : T
{
    friend Wrap<T> make_wrapper<T,nullptr>( T );
private:
    Wrap( T v ) : T( v ) {}
};

template<typename T>
class Imp
{
    T x;
public:
    Imp( T v ) {}
};

int main()
{
    auto wrap = make_wrapper( Imp<int>( 1 ) );
    return 0;
}

铛++:

$ clang++ --version
Debian clang version 3.5-1~exp1 (trunk) (based on LLVM 3.5)
Target: x86_64-pc-linux-gnu
Thread model: posix

$ clang++ -std=c++11 test.cpp
test.cpp:8 : 12 : error : calling a private constructor of class 'Wrap<Imp<int> >'
return Wrap<T>( i );
^
test.cpp:30 : 17 : note : in instantiation of function template specialization 'make_wrapper<Imp<int>, nullptr>' requested here
auto wrap = make_wrapper( Imp<int>( 1 ) );
^
test.cpp:16 : 5 : note : declared private here
Wrap( T v ) : T( v ) { }
^
1 error generated.

CL

Microsoft Visual Studio Professional 2013
Version 12.0.30501.00 Update 2

1>------ Build started: Project: Test1, Configuration: Debug Win32 ------
1>  Test1.cpp
1>  Test1.vcxproj -> C:\cygwin64\home\username\Test1\Debug\Test1.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

1 个答案:

答案 0 :(得分:1)

模板朋友是notoriously complicated。我不确定Clang是否正确,但可能是你在函数模板参数中的SFINAE技巧与

相反

14.5.4朋友[temp.friend]

  

9当朋友声明引用函数的特化时   模板,函数参数声明不得包含   默认参数,内联说明符也不应用于此类   声明。

C ++ 11为函数模板引入了默认模板参数,并且可能是clang将上述内容解释为g ++ / MSVC。可以通过在返回类型上执行SFINAE来修复它:

#include<type_traits>

template<typename T> class Wrap;

template<typename T>
using WrapRet = typename std::enable_if<std::is_class<T>::value, Wrap<T>>::type;

template<typename T>
WrapRet<T> make_wrapper( T i )
{
    return Wrap<T>( i );
}

template<typename T>
class Wrap : T
{
    friend WrapRet<T> make_wrapper<T>( T );
private:
    Wrap( T v ) : T( v ) {}
};

template<typename T>
class Imp
{
    T x;
public:
    Imp( T v ) {}
};

int main()
{
    auto wrap = make_wrapper( Imp<int>( 1 ) );
    return 0;
}

Live Example适用于clang和g ++。