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类似的方案无需工作.
该std::is_class<>特点就是做工精细,并且编译器是相当多告诉你的问题是什么:
TEST.CPP:14:17:注意:从参数1没有已知的转换
Foo* const到const 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)