Boost logo

Boost :

From: scleary_at_[hidden]
Date: 2000-02-24 16:32:30


I wrote:
> #define BOOST_CT_ASSERT( B ) \
> static enum { BOOST_JOIN(_boost_assert_enum_, \
> __LINE__) = sizeof(::boost::ct_assert<(B)>) }
>

Silly me. Of course this won't work. See the other macro I suggested
and my remarks actually make sense :)

OK. Let's look at YARDA (Yet Another Radically Different Approach :)

The 'enum' is good, but has linkage issues. 'static' is ok, but is
deprecated and restricts usage (in addition to the restrictions posted
earlier, it can't be used in unnamed classes); also, you can get plenty
of 'xxx initialized but never used' warnings. So let's try. . . um. .
. function declarations!

Consider:
namespace boost {
template<bool> ct_assert;
template<> ct_assert<true> { };
}

Looking at class scope (when COND is false):
  void unique_name(::boost::ct_assert<false>);
  void unique_name(::boost::ct_assert<COND>);
is illegal [9.3/2], whereas (when COND is true):
  void unique_name(::boost::ct_assert<false>);
  void unique_name(::boost::ct_assert<COND>);
is legal (overload).

But they are both legal at namespace/function scope, unless. . . um. .
. we add a default argument!

Now (when COND is false):
  void unique_name(::boost::ct_assert<false>);
  void unique_name(::boost::ct_assert<COND> = ::boost::ct_assert<true>(
));
will fail at the correct place [8.3.6/5].

But there's a problem! Implicit class template instantiation will not
instantiate the default argument. . . but it's not a problem, because
the function can't be redeclared in a class anyway, so it's OK!
Implicit function template instantiation should fail on the default
argument just like the usage in a normal function.

Limitations:
 . Cannot be used in "extern C" functions
 . Two different error messages, depending on where it's used:
     "cannot convert"/"invalid default parameter type", and
     "multiple declaration"
 . Apparently, compiler support is sketchy

Also, am I reading [8.3.6/5] correctly, above? Specifically, the
sentence I'm looking at is "The names in the expression are bound, and
the semantic constraints are checked, at the point where the default
argument expression appears" (except for function members of template
classes). I am reading this to mean that the conversions for default
arguments are checked at the point of the function declaration (NOT
definition!) -- but this would seem to indicate that this would require
the function argument to have a complete type, which is not specified
as necessary via [3.2/4], which says function arguments only have to be
complete types at definition or call (NOT declaration!). But maybe,
since default function arguments use copy-initialization semantics,
[3.2/4] would apply though the definition of an object (the parameter)
of type T.

Anyway, the code follows. Note that the comments starting with
"should" means that BCB5 fails to fail to compile (in other words, it
compiles without complaint, but should stop with error). Specifically,
BCB5 fails on usage in member functions and template classes --
violating [8.3.6/5] and [14.7.1/1], respectively.

Each time we get closer!
        -Steve

----------

namespace boost {

template <bool> struct ct_assert;
template <> struct ct_assert<true> { };

} // namespace boost

#define BOOST_POSTULATE_HELPER_DO_JOIN(x, y) x ## y

#define BOOST_POSTULATE_HELPER_JOIN(x, y) \
  BOOST_POSTULATE_HELPER_DO_JOIN(x, y)

#define BOOST_POSTULATE(cond) \
  void BOOST_POSTULATE_HELPER_JOIN(_boost_postulate_details_, __LINE__)
\
      (::boost::ct_assert<false>); \
  void BOOST_POSTULATE_HELPER_JOIN(_boost_postulate_details_, __LINE__)
\
      (::boost::ct_assert<(cond)> = ::boost::ct_assert<true>())

// Namespace scope
BOOST_POSTULATE(sizeof(int) == 4);
BOOST_POSTULATE(sizeof(char) == 1);
//BOOST_POSTULATE(sizeof(int) == sizeof(char)); // will not compile

// Function (block) scope
void f()
{
  BOOST_POSTULATE(sizeof(int) == 4);
  BOOST_POSTULATE(sizeof(char) == 1);
// BOOST_POSTULATE(sizeof(int) == sizeof(char)); // will not compile

  // Local class scope
  struct EmmaWoodhouse
  {
    BOOST_POSTULATE(sizeof(int) == 4);
    BOOST_POSTULATE(sizeof(char) == 1);
// BOOST_POSTULATE(sizeof(int) == sizeof(char)); // will not compile
  };
}

struct Bob
{
  private: // can be in private, to avoid namespace pollution
    BOOST_POSTULATE(sizeof(int) == 4);
    BOOST_POSTULATE(sizeof(char) == 1);
// BOOST_POSTULATE(sizeof(int) == sizeof(char)); // will not compile
  public:

  // Member function scope: provides access to member variables
  int x;
  char c;
  int f()
  {
#ifndef _MSC_VER // broken sizeof in VC6
    BOOST_POSTULATE(sizeof(x) == 4);
    BOOST_POSTULATE(sizeof(c) == 1);
// BOOST_POSTULATE(sizeof(x) == sizeof(c)); // should not compile
#endif
    return x;
  }
};

// Template class scope
template <class Int, class Char>
struct Bill
{
  private: // can be in private, to avoid namespace pollution
    BOOST_POSTULATE(sizeof(Int) == 4);
    BOOST_POSTULATE(sizeof(Char) == 1);
// BOOST_POSTULATE(sizeof(Int) == sizeof(Char)); // should not
compile when instantiated
  public:

  // Template member function scope: provides access to member variables
  Int x;
  Char c;
  template <class Int2, class Char2>
  void f(Int2 y, Char2 d)
  {
    BOOST_POSTULATE(sizeof(Int) == sizeof(Int2));
    BOOST_POSTULATE(sizeof(Char) == sizeof(Char2));
// BOOST_POSTULATE(sizeof(Int) == sizeof(Char)); // will not compile
when instantiated
  }
};

void test_Bill() // BOOST_POSTULATEs are not triggerred until
instantiated
{
  Bill<int, char> z;
// Bill<int, int> bad; // should not compile
  int i = 3;
  char ch = 'a';
  z.f(i, ch);
// z.f(i, i); // will not compile
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk