From: igodard@pacbell.net   
      
   On 9/6/2012 1:46 AM, Francis Glassborow wrote:   
   > On 06/09/2012 00:51, Ivan Godard wrote:   
   >> On 9/5/2012 2:53 PM, Casey Carter wrote:   
   >>> On 2012-09-05 02:48, Ivan Godard wrote:   
   >>>   
      
   >>>> I have a template class taking a typename T argument, and need to   
   >>>> define a differenceType representing the abstract "distance"   
   >>>> between any pair of values. The template is instantiated with   
   >>>> enums, built-in types, and random user classes that define   
   >>>> operator-(T, T). This difference type was initially declared as:   
   >>>> typedef typeof(T() - T()) differenceType;   
   >>>>   
   >>>> I recently converted an existing enum to a C++11 "enum class",   
   >>>> and the above broke because operator- was not defined for enum   
   >>>> classes and there is no conversion to something that defines it.   
   >>>   
   >>> This is exactly the use case for std::declval(): "creating" an   
   >>> expression of type T for use in non-evaluated contexts - e.g.,   
   >>> decltype(), sizeof() - without needing a valid constructor   
   >>> expression. Try:   
   >>>   
   >>> typedef   
   >>> decltype(std::declval() - std::declval()) differenceType;   
   >>>   
   >>>   
   >>   
   >> Thank you; this gets rid of the default constructors and the use of   
   >> typeof, although it still leaves me with my original issue: how to   
   >> figure out that operator- is not defined.   
   >   
   > But arithmetic operators are never defined for user defined types   
   > unless the user chooses to declare and define them. There is a very   
   > limited set of operators that are defined for user defined   
   > class/struct types (operator=, operator&, and several operators that   
   > cannot be user defined such as sizeof). That makes it easy to figure   
   > out, unless you define them they are not defined.   
      
   { Quoted signature removed -mod }   
      
   Yes, I am aware that arithmetic operators are not defined for user   
   classes. In my case, sometimes the "element" template was invoked with   
   built-in types that define operator-, like int; sometimes with types   
   that have conversions to something with operator-, like unscoped   
   enums, and sometimes with user classes that explicitly defined   
   operator-. However, it was never invoked with things for which   
   operator- could not be reached, until some unscoped enums were changed   
   to scoped enums and broke the usage of "element". I wanted to support   
   the change to scoping enums, which are certainly better than unscoped   
   although still only a half-measure, but could not figure out how to do   
   so until helped by Daniel.   
      
   As for "easy to figure out", call me dense but it sure wasn't easy for   
   me. Even Daniel's solution, while solving my problem with scoped   
   enums, does not provide a general solution to discovering whether a   
   particular operation is defined.   
      
   So please prove it is easy: I challenge you to write the   
   generalization of my use case:   
      
   Write a template function taking a single argument of arbitrary   
   type. If that type defines member function "foo", call it; if it does   
   not define "foo" then call member function "bar"; if neither are   
   defined then fail with a suitable diagnostic.   
      
   Test case:   
   template void fooOrBar(T t) {   
    /* you write this, with the following effect: */   
    if (defined(t.foo))   
    t.foo();   
    else   
    t.bar();   
    /* end of your code */   
    }   
   struct FOO { void foo() {}; };   
   struct BAR { void bar() {}; };   
   int main() {   
    FOO f;   
    BAR b;   
    fooOrBar(f);   
    fooOrBar(b);   
    return 0;   
    }   
      
   Your solution should work for any argument type for which "t.foo()" is   
   valid, including references and CV-qualified. Note that FOO and BAR   
   are supplied by third parties and your solution cannot change   
   them. Note also that foOrBar will be placed in a utility library and   
   so you cannot simply enumerate the list of possible argument types in   
   advance and write an overload for each.   
      
   For extra points, extend the problem to built in operators like   
   operator-, such that any argument for which "-t" is valid will apply   
   "-t" and otherwise will call "bar(t)". The extension should extend   
   support to unscoped enums and all arithmetic and pointer types.   
      
   If you protest that the problem is artificial and no one would write   
   code that needed this kind of thing, I respond with my real-world   
   environment: integrating API libraries from multiple vendors in   
   support of a common user API supporting both. Vendors have the   
   annoying trait of spelling similar operations differently; one says   
   "pushButton()", one says "push_button()", and your job is to provide a   
   clean interface to both that says "prod()" to get the appropriate   
   thing done on whichever kind of argument your code receives.   
      
      
   --   
    [ 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)   
|