Built-in type traits

Question regarding http://msdn2.microsoft.com/library/ms177194(en-us,vs.80).aspx
__has_nothrow_xxx seem to demand ctor, copy & assignment to have explicit nothrow declaration, contrary to what the docs say: "__has_nothrow_constructor(type) Returns true if the default constructor has an empty exception specification or can be deduced to never throw an exception."
struct A
{
A() {} // clearly does not throw, but __has_nothrow_constructor returns false
};

Thanks,
- NK

[512 byte] By [narechk] at [2007-12-16]
# 1
After taking a closer look it appears the support for compiler intrinsic type traits in Beta2 is implemented only partially:
typedef int T;
__is_pod(T);
__has_trivial_constructor(T);
__has_trivial_copy(T);
__has_trivial_assign(T);
__has_trivial_destructor(T);
__has_nothrow_constructor(T);
__has_nothrow_copy(T);
__has_nothrow_assign(T);
Ditto for the rest of fundamental types. All of the above return false, which AFAIK is incorrect! [§3.9, ?10; §9, ?4]
struct A
{
A() {}
A(const A&) {}
const A& operator=(const A&) {}
};
typedef A T;
__is_pod(T); // false
__has_trivial_constructor(T); // false
__has_trivial_copy(T); // false
__has_trivial_assign(T); // false
__has_trivial_destructor(T); // true
__has_nothrow_constructor(T); // false, too conservative
__has_nothrow_copy(T); // false, too conservative
__has_nothrow_assign(T); // false, too conservative
The compiler is too conservative regarding nothrow, it should be able to deduce that constructor, copy and assign can never throw.
struct B
{
B() throw() {}
B(const B&) throw() {}
const B& operator=(const B&) throw() {}
};
typedef B T;
__is_pod(T); // false
__has_trivial_constructor(T); // false
__has_trivial_copy(T); // false
__has_trivial_assign(T); // false
__has_trivial_destructor(T); // true
__has_nothrow_constructor(T); // true
__has_nothrow_copy(T); // true
__has_nothrow_assign(T); // true
It seems the compiler needs an explicit nothrow statement in order for ctor, copy and assign to be qualified as nothrow. Presumably the result of nothrow deduction is not fed to the intrinsics correctly in this version, which is a pity, really, since these built-ins are invaluable for providing optimization opportunities within a library.
Can someone confirm the above. Will the final release of the compiler implement type traits intrinsics correctly?
Thanks,
- NK

--
Sunsys Dox - A C++ documentation system
For programmers, by programmers.
http://dox.isfotek.se/

narechk at 2007-9-9 > top of Msdn Tech,Visual C++,Visual C++ Language...
# 2
Jason Shirk was kind enough to answer this at boost mailing lists. The answer is included verbatim below:
>> --Original Message--
>> From: narechk [mailto:narechk@...]
>> Sent: Wednesday, July 13, 2005 10:29 AM
>> Subject: Re: VC8 type traits documentation
>>
>>
>> It appears the support for compiler intrinsic type traits in Beta2 is
>> implemented only partially:
>>
>> typedef int T;
>> __is_pod(T);
>> __has_trivial_constructor(T);
>> __has_trivial_copy(T);
>> __has_trivial_assign(T);
>> __has_trivial_destructor(T);
>> __has_nothrow_constructor(T);
>> __has_nothrow_copy(T);
>> __has_nothrow_assign(T);
>>
>> Ditto for the rest of fundamental types. All of the above return false,
>> which AFAIK is incorrect! [§3.9, ?10; §9, ?4]
>>

The compiler intrinsics are only there to provide the type information that is otherwise unavailable. Put another way, for fundamental types, we decided we don't care what the value is (we default to false) since an implementation of type traits can get the right value.
This simplifies the implementation and puts the burden on the library implementation which can change more easily than the compiler.

>> struct A
>> {
>> A() {}
>> A(const A&) {}
>> const A& operator=(const A&) {}
>> };
>>
>> typedef A T;
>> __is_pod(T); // false
>> __has_trivial_constructor(T); // false
>> __has_trivial_copy(T); // false
>> __has_trivial_assign(T); // false
>> __has_trivial_destructor(T); // true
>> __has_nothrow_constructor(T); // false, too conservative
>> __has_nothrow_copy(T); // false, too conservative
>> __has_nothrow_assign(T); // false, too conservative
>>
>> The compiler is too conservative regarding nothrow, it should be able to
>> deduce that constructor, copy and assign can never throw.
>>
>> struct B
>> {
>> B() throw() {}
>> B(const B&) throw() {}
>> const B& operator=(const B&) throw() {}
>> };
>>
>> typedef B T;
>> __is_pod(T); // false
>> __has_trivial_constructor(T); // false
>> __has_trivial_copy(T); // false
>> __has_trivial_assign(T); // false
>> __has_trivial_destructor(T); // true
>> __has_nothrow_constructor(T); // true
>> __has_nothrow_copy(T); // true
>> __has_nothrow_assign(T); // true
>>
>> It seems the compiler needs an explicit nothrow statement in order for
>> ctor, copy and assign to be qualified as nothrow. Presumably the result
>> of nothrow deduction is not fed to the intrinsics correctly in this
>> version.
>>
>> Can someone comment on the above.
>>

You are correct that the compiler _could_ deduce nothrow in your example, but in general the compiler couldn't (for example, if the definition of the function is in the current translation unit), and therefore shouldn't try.
--
Jason Shirk
VC++ Compiler Team

narechk at 2007-9-9 > top of Msdn Tech,Visual C++,Visual C++ Language...