为什么is_class <T>不能在此代码段中运行?

qwe*_*304 1 c++ templates type-traits c++11

尝试在以下段中使用is_class(从较大的段中删除),但它似乎不起作用.怎么了?

#include <type_traits>

template<typename U, typename = void>
struct xxxU_Impl
{
    static void xxxU_push (const U& value);
};

template<typename U> void xxxU_push (const U& value) { xxxU_Impl<U>::xxxU_push (value); }

template<typename U>
struct xxxU_Impl<U *, typename std::enable_if<std::is_class<U>::value>::type>
{
    static void xxxU_push (const U *& value) { }
};

class Foo
{
public:
    int mFoo;
};

int main () {
    Foo * pFoo = new Foo;

    xxxU_push<Foo *>(pFoo);
}
Run Code Online (Sandbox Code Playgroud)

这是在cygwin上的gcc v4.7.2和gcc -std = c ++ 11 test.cpp命令行.

输出是:

test.cpp: In instantiation of 'void xxxU_push(const U&) [with U = Foo*]':
test.cpp:26:23:   required from here
test.cpp:9:63: error: no matching function for call to 'xxxU_Impl<Foo*, void>::xxxU_push(Foo* const&)'
test.cpp:9:63: note: candidate is:
test.cpp:14:17: note: static void xxxU_Impl<U*, typename std::enable_if<std::is_class<_Tp>::value>::type>::xxxU_push(const U*&) [with U = Foo]
test.cpp:14:17: note:   no known conversion for argument 1 from 'Foo* const' to 'const Foo*&'
Run Code Online (Sandbox Code Playgroud)

**

更新

:**这是带有注释的修改代码,恕我直言显示类型现在是相同的.不过,我收到编译错误.

#include <type_traits>

template<typename U, typename = void>
struct xxxU_Impl
{
    static void xxxU_push (const U  & value);   // U=Foo*:  const Foo* & value ==
                                                //          Foo const * & value
};

template<typename U> void xxxU_push (const U  & value)  // U=Foo*:  const Foo* & value ==
                                                        //          Foo const * & value
{ xxxU_Impl<U>::xxxU_push (value); }

template<typename U>
struct xxxU_Impl<U *, typename std::enable_if<std::is_class<U>::value>::type>
{
    static void xxxU_push (U const * & value) { }   // U=Foo:   Foo const * & value
};

class Foo
{
public:
    int mFoo;
};

int main () {
    Foo* pFoo = new Foo;

    xxxU_push<Foo*>(pFoo);
}
Run Code Online (Sandbox Code Playgroud)

怎么了?

Thx,D

PS与is_enum类似的方案无需工作.

And*_*owl 7

std::is_class<>特点就是做工精细,并且编译器是相当多告诉你的问题是什么:

TEST.CPP:14:17:注意:从参数1没有已知的转换Foo* constconst Foo*&

您正在以这种方式调用函数模板:

xxxU_push<Foo *>(pFoo);
Run Code Online (Sandbox Code Playgroud)

这意味着U将是Foo*.现在功能签名:

template<typename U>
void xxxU_push (const U& value)
Run Code Online (Sandbox Code Playgroud)

相当于:

template<typename U>
void xxxU_push (U const& value)
Run Code Online (Sandbox Code Playgroud)

和更换后Foo*U你会得到这样的:

void xxxU_push (Foo* const& value)
Run Code Online (Sandbox Code Playgroud)

因此,value是指向a的指针的常量引用Foo.在函数内部,您可以通过以下方式实例化类模板:

xxxU_Impl<U>::xxxU_push (value);
Run Code Online (Sandbox Code Playgroud)

这就是,当替换Foo*U再次:

xxxU_Impl<Foo*>::xxxU_push (value);
Run Code Online (Sandbox Code Playgroud)

现在,您的类模板特化以这种方式定义:

template<typename U>
struct xxxU_Impl<U *, typename std::enable_if<std::is_class<U>::value>::type>
{
    static void xxxU_push (const U *& value) { }
};
Run Code Online (Sandbox Code Playgroud)

如果您正在使用实例它Foo*作为一个模板参数,U将被推断为Foo,这一个类类型.因此,您的类模板会在没有失败的情况下实例化(不确定这是您想要的,但这肯定会发生什么),特别是xxxU_push()函数以这种方式实例化:

 static void xxxU_push (const Foo *& value) { }
Run Code Online (Sandbox Code Playgroud)

这相当于:

 static void xxxU_push (Foo const*& value) { }
Run Code Online (Sandbox Code Playgroud)

你能看到区别么?在调用站点上,你有一个非常量指针的常量引用,这里你有一个常量指针的非常量引用!这两种类型不同,编译器抱怨它无法转换参数.

例如,您可以通过更改签名来修复错误,xxxU_push()如下所示:

static void xxxU_push (U * const& value) { }
//                     ^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

在这个改变之后,你可以在这里看到整个事情的编译.

更新:

作为评论的后续内容,事实证明您必须希望static成员函数xxxU_push()接受指向以下内容的指针const:

 static void xxxU_push (Foo const*& value) { }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您将不得不做出决定:您不能将a传递Foo*给接受对指针的非常量引用的函数const.但是,您可以删除参考:

 static void xxxU_push (Foo const* value) { }
Run Code Online (Sandbox Code Playgroud)

这是使程序编译的第一种可能性.第二种可能性是更改调用站点,以便它提供指向以下内容的指针const:

int main () {
    Foo * pFoo = new Foo;
    Foo const* pConstFoo = pFoo;
    xxxU_Impl<Foo*>::xxxU_push(pConstFoo);
//                             ^^^^^^^^^
}
Run Code Online (Sandbox Code Playgroud)