$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [boost] [type trait extension] I hate volatile...
From: Frédéric Bron (frederic.bron_at_[hidden])
Date: 2011-07-22 04:44:01
> What does your code look like that detects void types?  I use the following
> EXPR_IS_VOID macro myself (which is not originally mine, but I think I have
> modified it from the original after some testing); feel free to pilfer.  The
> double comma operator thingy is intended to work even if the type of ( Expr
> ) has an overloaded comma operator, but I've found that GCC has issues with
> this construct, hence the two versions.
Thank you for help. I have tested your code for void detection which
GNUC version gives identical results to the one I use (on msvc, g++
and intel):
namespace detail {\
        struct returns_void_t {};
        static ::boost::type_traits::yes_type returns_void(returns_void_t);\
        static ::boost::type_traits::no_type returns_void(int);\
}
template <typename T> int operator,(const T&, ::detail::returns_void_t);
template <typename T> int operator,(const volatile T&,
::detail::returns_void_t);
#define RETURNS_VOID_IMPL(Expr)\
                sizeof(::boost::type_traits::yes_type)\
                ==\
                sizeof(::detail::returns_void(((Expr), ::detail::returns_void_t())))
Here are the results (best viewed in fixed size font) of void detection with
functions returning various types (int of class X) with various cv qualifiers
and by-value or reference:
                     | g++ | g++ |icpc |msvc |
return type          |4.3.2|4.5.2|10.0 | 10  |
                     |4.3.4|4.5.3|11.1 |     |
                     |4.4.4|4.6.0|12.0 |     |
void                 |  1  |  1  |  1  |  1  |
int                  |  0  |  0  |  0  |  0  |
int const            |  0  |  0  |  0  |  0  |
int volatile         |  1  |  0  |  0  |  0  |
int const volatile   |  1  |  0  |  0  |  0  |
int &                |  0  |  0  |  0  |  0  |
int const &          |  0  |  0  |  0  |  0  |
int volatile &       |  0  |  0  |  0  |  0  |
int const volatile & |  0  |  0  |  0  |  0  |
X                    |  0  |  0  |  0  |  0  |
X const              |  0  |  0  |  0  |  0  |
X volatile           |  1  |  1  |fail |  0  |
X const volatile     |  1  |  1  |fail |  0  |
X &                  |  0  |  0  |  0  |  0  |
X const &            |  0  |  0  |  0  |  0  |
X volatile &         |  0  |  0  |  0  |  0  |
X const volatile &   |  0  |  0  |  0  |  0  |
So only msvc gives the right answer, i.e. detects void returning only when void
returning. g++ from version 4.5 says that any cv qualifiers for by-value int is
ignored which improves the answer for those return types but returning a class
by value with volatile qualifiers fails to complile with intel compiler and
gives the wrong answer with g++. I wonder why the code gives the right answer
withmsvc.
I found another issue with g++ (all versions up to 4.6.0) (works fine
with msvc 10
and intel 12): although g++ behaves well with fundamental types
returned by value,
the result of postfix operator++ applied to an int volatile is detected as void!
The standard states in 13.6/3 (Built-in operators):
"For every pair (T, VQ), where T is an arithmetic type, and VQ is
either volatile
or empty, there exist candidate operator functions of the form
VQ T& operator++(VQ T&);
T operator++(VQ T&, int);"
That means that for an "int volatile" variable the corresponding built-in
operator should be:
int operator++(int volatile &, int);
and according to the table above this should be correctly detected as returning
non-void. Note that prefix operator++ works fine.
This is the program that fails (writes true) with g++ (4.5.2 and 4.6.0):
#include <iostream>
#include <iomanip>
#include <boost/type_traits/detail/yes_no_type.hpp>
namespace detail {\
   struct returns_void_t {};
   static ::boost::type_traits::yes_type returns_void(returns_void_t);\
   static ::boost::type_traits::no_type returns_void(int);\
}
template <typename T> int operator,(const T&, ::detail::returns_void_t);
template <typename T> int operator,(const volatile T&,
::detail::returns_void_t);
#define RETURNS_VOID(Expr)\
   sizeof(::boost::type_traits::yes_type)\
   ==\
   sizeof(::detail::returns_void(((Expr), ::detail::returns_void_t())))
int main() {
   int volatile one_int_volatile;
   std::cout<<std::boolalpha<<"RETURNS_VOID:
"<<(RETURNS_VOID((one_int_volatile++)))<<'\n';
   return 0;
}
Frédéric