From: daniel.kruegler@googlemail.com   
      
   Am 10.06.2012 07:02, schrieb Daryle Walker:   
   > I decided to make the conversion operator only work when the   
   > conversion from T to U is implicit. So I added an SFINAE condition:   
   >   
   > //...   
   > #include    
   > #include    
   > //...   
   > template <   
   > typename U,   
   > typename std::enable_if<   
   > std::is_convertible::value,   
   > std::nullptr_t   
   > >::type...   
   > >   
   > constexpr   
   > operator MyArray() const;   
   > //...   
   >   
   > I used the index_tuple trick to implement this member function   
   > template, returning a brace-initializer expression.   
      
   What is a "brace-initializer expression"? Do you mean a braced-init-list   
   such as   
      
   { /expression-list/ };   
      
   ? This is *no* expression.   
      
   I also wonder why you added the std::nullptr_t argument. You could just   
   remove it, because std::enable_if has a default template type of void.   
      
   > Then I decided   
   > to extend this with a second conversion operator, this time for   
   > types that can convert non-implicitly:   
   >   
   > //...   
   > template <   
   > typename V,   
   > typename std::enable_if<   
   > !std::is_convertible::value   
   > && std::is_constructible::value,   
   > std::nullptr_t   
   > >::type...   
   > >   
   > explicit constexpr   
   > operator MyArray() const;   
   > //...   
   >   
   > The internal code is just like the first operator, but the   
   > initializers around surrounded by "static_cast" before variadic   
   > expansion.   
      
   Well yes, static_cast is different from a direct-initialization. Btw.   
   you don't even need a class enum for this. The same kind of static_cast   
   conversion is necessary when you convert a classic (i.e. unscoped)   
   enumeration type to arithmetic type.   
      
   > Now I needed to test this code with two types that convert, but not   
   > implicitly. (I've been using the built-in arithmetic types, but all   
   > conversions between them are implicit, even the narrowing ones!) I   
   > thought making a custom class-type type with explicit constructors   
   > and/or operators for this, but decided to go with the new-fangled   
   > enum-class type, which don't have the implicit conversions to int   
   > that classic enums do.   
   >   
   > I hit a wall, but it was a good thing I did it, since I would have   
   > missed a use case if I used a class-type.   
   >   
   > When converting between an enum-class and a built-in numeric type,   
   > you need to explicitly write a "static_cast":   
   >   
   > //...   
   > enum class two_bit_t   
   > : unsigned   
   > { zero, one, two, three };   
   >   
   > two_bit_t const v = two_bit_t::two;   
   > unsigned const vv = v; // ERROR   
   > unsigned const vv{ v }; // ERROR   
   > auto const vv = static_cast( v ); // WORKS   
   > //...   
   >   
   > My tests had a conversion between MyArray and   
   > MyArray, but it never triggered. After trying many   
   > guesses, I got this to work:   
   >   
   > //...   
   > // Comment out BOTH of the previous conversion operators   
   > template < typename W >   
   > constexpr   
   > operator MyArray() const;   
   > //...   
   >   
   > This operator template called the internal function that used a   
   > "static_cast" wrapper. But why didn't the previous version work?   
   > Because static_cast covers implicit conversions; conversions that   
   > can use the constructor(-like) syntax, which std::is_constructible   
   > covers; plus several others! Enum-class to built-in integer is one   
   > of those other conversions.   
      
   Correct. Another situation is a cast from void* to int*, or the   
   conversion of Base& to Derived&.   
      
   > I can't use SFINAE to restrict conversions just to explicitly-   
   > convertible types; I have to make a general version (or general   
   > minus implicit) and just have the compiler choke within the   
   > conversion function when it encounters two types with no static_cast   
   > path, instead of having it error-out in advance via SFINAE.   
   >   
   > (Does anyone know of a better workaround?)   
      
   What you are asking for is a trait like is_static_castable. This is   
   really very easy to implement, e.g. like so:   
      
   #include    
      
   struct is_static_castable_impl   
   {   
    template(std::declval()))   
    >   
    static std::true_type test(int);   
      
    template   
    static std::false_type test(...);   
   };   
      
   template   
   struct is_static_castable :   
    decltype(is_static_castable_impl::test(0))   
   {   
   };   
      
   > The problem for us is that there is NO type-trait class template   
   > that covers explicit conversions that only have the static_cast   
   > operator as their only path (besides C-casts). We should add this,   
   > and the trivial & no-throw variants, to the TS2 (or whatever we're   
   > calling the next minor update to C++).   
      
   I weakly agree, because this trait is really easy to implement, see   
   above. I used is_static_castable internally to implement   
   is_constructible as a pure library-based emulation, because the hard   
   part of implementing is_constructible is the two-argument-case. This is   
   so, because the most natural way to emulate this is to use a functional   
   cast using an expression of the form T(std::declval()), but this is   
   equivalent to the "C cast": (T) std::declval(). is_static_castable   
   helps to filter away the otherwise valid reinterpret_cast and const_cast   
   interpretations, so you can then - in a second step - filter away the   
   remaining cases that are unique for static_cast compared to direct   
   initialization.   
      
   Before adding is_static_castable and it's nothrow/trivially variants I   
   rather would prefer to see is_nothrow_convertible and   
   is_trivially_convertible, which are really missing given the   
   corresponding is_XX_constructible traits.   
      
   Greetings from Bremen,   
      
   Daniel Krügler   
      
      
      
      
   --   
    [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
    [ comp.lang.c++.moderated. First time posters: Do this! ]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|