Search code examples
c++staticconstantstypedefdecltype

std::result_of applied to const overloaded methods


If I give

typedef std::vector<int> v;

Then the below can be used to capture the type of the constant iterator (an alternative is to use v::const_iterator, but this depends on the const_iterator member type being explicitly defined in the class.

typedef typename std::result_of<decltype(&v::cbegin)(v*)>::type const_iterator;

Indeed, we can check that the above does as we want.

static_assert(std::is_same<const_iterator, typename v::const_iterator>::value);

However, I find a compiler failure on the below.

typedef typename std::result_of<decltype(&v::begin)(v*)>::type iterator;

The compiler complains that the method is overloaded (by const modifier) and cannot be unambiguously resolved. However, I cannot find out the syntax to resolve the ambiguity. At a minimum, one expects the below to be unambiguous, because only the const version can operate on a const object. However, even the below is similarly problematic.

typedef typename std::result_of<decltype(&v::begin)(const v*)>::type const_iterator2;

How do I refer to a particular const or nonconst version of begin?


Solution

  • The following does what you want:

    using v = std::vector<int>;
    using iter = decltype(std::declval<v>().begin());
    static_assert(std::is_same<iter, typename v::iterator>::value);
    

    The issue here is that &v::begin is ambiguous. There are two v::begin functions, and the & operator has no way to know which one to return the address of. Using std::declval gets around that. Since the return type of std::declval<v>() is v, the compiler knows you're interested in the non-const v::begin().

    Similarly, the following gets you the const version:

    using citer = decltype(std::declval<const v>().begin());
    static_assert(std::is_same<citer, typename v::contst_iterator>::value);
    

    Note that no objects are created in this code. std::declval has no definition, so it only works in unevaluated contexts like decltype.