Decltype (auto) in a member function ignores an invalid object, decltype (expr) does not work

I have a simple template wrapper structure with a member function that calls .error()on an object of its template type.

template <typename T>
struct Wrapper {
    T t;
    decltype(auto) f() {
        return t.error(); // calls .error()
    }
};

If I create an instance of this type with a type that does not have a member function error(), it is fine if I do not name it. This is the behavior that I want.

Wrapper<int> w; // no problem here
// w.error(); // uncommented causes compilation failure

If I use what I thought was the semantic equivalent with a return type, these are errors in the variable declaration

template <typename T>
struct Wrapper {
    T t;
    auto f() -> decltype(t.error()) {
        return t.error();
    }
};

Wrapper<int> w; // error here

I agree that the two are not semantically equivalent, but do you still need the behavior of the first to use the return type (only C ++ 11) without specializing in the whole class with some kind of HasErrortmp trickery?

+4
2

decltype(auto) f();
auto f() -> decltype(t.error());

, . [dcl.spec.auto]/12. - , , .

Wrapper , ( ) - [temp.inst]/1. decltype(auto) f(); , . , auto f() -> decltype(t.error()); .


++ 11 , . f :

template<typename U = T>
auto f() -> decltype( std::declval<U&>().error() );

:

template<typename U = T>
auto f() -> decltype( std::declval<U&>().error() )
{
    return t.error();
}

Wrapper, t.error() , f , . [temp.res]/8, , , :

, , , .

, , , , . ; , . , .


, , ( ):

#include <type_traits>

template<typename T> struct type_is { using type = T; };

template <typename T>
struct Wrapper {
    T t;

    template<typename U=T, typename=void>
    struct error_return_type_or_void : type_is<void> {};

    template<typename U>
    struct error_return_type_or_void
        <U, decltype(std::declval<U&>().error(), void())>
    : type_is<decltype(std::declval<U&>().error())> {};

    auto f() -> typename error_return_type_or_void<>::type {
        return t.error();
    }
};
+5

- crtp.

  // todo:
  template<class T>
  struct has_error; // true_type if T.error() is valid

  template<class D,class T,bool Test=has_error<T>{}>
  struct do_whatever {
    D* self(){return static_cast<D*>(this);}
    D const* self()const{return static_cast<D const*>(this);}

    auto f()->decltype(self()->t.error()) {
      return self()->t.error();
    }
  };
  template<class D,class T>
  struct do_whatever<D,T,false>{};

now f() , T error().

+2

All Articles