C++ 为什么使用两个sizeofs检查一个类是否可以默认构造,而使用一个则不能?
我使用了“”中的代码 我对其进行了轻微修改,以处理所有测试用例:C++ 为什么使用两个sizeofs检查一个类是否可以默认构造,而使用一个则不能?,c++,templates,metaprogramming,C++,Templates,Metaprogramming,我使用了“”中的代码 我对其进行了轻微修改,以处理所有测试用例: template< class T > class is_default_constructible { typedef int yes; typedef char no; // the second version does not work #if 1 template<int x, int y> class is_equal {}; template<
template< class T >
class is_default_constructible {
typedef int yes;
typedef char no;
// the second version does not work
#if 1
template<int x, int y> class is_equal {};
template<int x> class is_equal<x,x> { typedef void type; };
template< class U >
static yes sfinae( typename is_equal< sizeof U(), sizeof U() >::type * );
#else
template<int x> class is_okay { typedef void type; };
template< class U >
static yes sfinae( typename is_okay< sizeof U() >::type * );
#endif
template< class U >
static no sfinae( ... );
public:
enum { value = sizeof( sfinae<T>(0) ) == sizeof(yes) };
};
我在这里真是不知所措:
int[100]
和NotDefaultConstructible
。使用两个模板参数版本,所有测试都成功std::is_default_constructible
。然而,我的问题是,为什么这两种实现有任何不同,为什么一种可以工作而另一种不能这几乎可以肯定是编译器的一个工件(bug),因为g++的行为(和失败)不同。我只能猜测为什么VS的行为不同,但有一个猜测似乎是合理的,那就是这个类:
template<int x> class is_okay { typedef void type; };
模板类是_ok{typedef void type;};
无论模板参数如何,都具有相同的定义,因此编译器在分析静态sfinae(typename是_ok::type*)时可能会跳过一步
并认为它定义得很好,而不仔细查看的参数是否正常
。所以它认为一切都是可以默认构造的
我不知道为什么VS和g++都不介意是不是可以::type
是私有的。看来他们两个都应该这样
另一方面,g++将这两个版本视为等效版本。但是,在这两种情况下,int[100]
会产生不同的错误。关于它是否应该是默认可构造的,这一点是有争议的。你似乎认为不应该这样。g++47的std::is_default_constructible
认为它是可构造的!要获得该行为(可能更标准),可以在enum
行中将T
替换为typename boost::remove_all_extends::type
。(我的答案从DS之前的答案中得到了很大的启示。)
首先,请注意,您有类is_ok{typedef void type;}
,即类型
是is_ok
的私有成员。这意味着它在类之外实际上是不可见的,因此
template< class U >
static yes sfinae( typename is_equal< sizeof U(), sizeof U() >::type * );
为什么不检查一下标准库中是否已经有了它?什么不起作用?它在g++上运行良好,除了
BOOST\u STATIC\u ASSERT(!is\u default\u constructible::value)代码>@B如果一个断言失败,并且该断言是正确的,那么它肯定不能正常工作?g++-4.7.1正确编译这两个变体。您应该使用typedef char yes[1];typedef字符编号[2]
以保证它们的大小不同(int
和char
理论上可以是相同的大小);而且我觉得它更容易阅读。你已经很好地解释了这一点。我将其设置为失败int[100]
,因为我编写了一个模板函数,其中包含一个可选参数T defaultValue=T()
,该参数在VS2010中不适用于T=int[100]
。直到现在我才知道默认值与值的初始化。
template< class U >
static yes sfinae( typename is_equal< sizeof U(), sizeof U() >::type * );
template< class T >
class is_default_constructible {
typedef int yes;
typedef char no;
template<int x> struct is_okay { typedef int type; };
template< class U >
static yes sfinae( typename is_okay< sizeof (*new U) >::type );
template< class U >
static no sfinae( ... );
public:
enum { value = sizeof( sfinae<T>(0) ) == sizeof(yes) };
};
#if __has_feature(cxx_static_assert)
#define BOOST_STATIC_ASSERT(x) static_assert(x, "or fail")
#else
#define dummy2(line) dummy ## line
#define dummy(line) dummy2(line)
#define BOOST_STATIC_ASSERT(x) int dummy(__COUNTER__)[(x) - 1]
#endif
#include <string>
BOOST_STATIC_ASSERT( !is_default_constructible<int()>::value );
BOOST_STATIC_ASSERT( is_default_constructible<bool>::value );
BOOST_STATIC_ASSERT( is_default_constructible<std::string>::value );
BOOST_STATIC_ASSERT( is_default_constructible<int[100]>::value );
BOOST_STATIC_ASSERT( is_default_constructible<const std::string>::value );
struct NotDefaultConstructible {
const int x;
NotDefaultConstructible( int a ) : x(a) {}
};
BOOST_STATIC_ASSERT( !is_default_constructible<NotDefaultConstructible>::value );
struct DefaultConstructible {
const int x;
DefaultConstructible() : x(0) {}
};
BOOST_STATIC_ASSERT( is_default_constructible<DefaultConstructible>::value );