#include <iostream>
#include <type_traits>
using namespace std;
template<typename FROM, typename TO>
struct CopyConstImpl {
using type = typename std::remove_const<TO>::type;
};
template<typename FROM, typename TO>
struct CopyConstImpl<const FROM, TO> {
using type = typename std::add_const<TO>::type;
};
template<typename FROM, typename TO>
struct CopyConst {
using type = typename CopyConstImpl<typename std::remove_reference<FROM>::type, TO>::type;
};
struct Foo {
int& bar() { return barImpl(*this); }
const int& bar() const { return barImpl(*this); }
private:
template<typename THIS>
static auto barImpl(THIS&& instance) -> typename CopyConst<THIS, int>::type& {
return instance.x;
}
int x = 5;
};
int main() {
static_assert(is_same<int&, decltype(declval<Foo>().bar())>::value,
"Non-const foo.bar() result must yield a non-const reference");
static_assert(is_same<const int&, decltype(declval<const Foo>().bar())>::value,
"Const foo.bar() result must yield a const reference");
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dHlwZV90cmFpdHM+CnVzaW5nIG5hbWVzcGFjZSBzdGQ7Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBGUk9NLCB0eXBlbmFtZSBUTz4Kc3RydWN0IENvcHlDb25zdEltcGwgewoJdXNpbmcgdHlwZSA9IHR5cGVuYW1lIHN0ZDo6cmVtb3ZlX2NvbnN0PFRPPjo6dHlwZTsKfTsKCnRlbXBsYXRlPHR5cGVuYW1lIEZST00sIHR5cGVuYW1lIFRPPgpzdHJ1Y3QgQ29weUNvbnN0SW1wbDxjb25zdCBGUk9NLCBUTz4gewoJdXNpbmcgdHlwZSA9IHR5cGVuYW1lIHN0ZDo6YWRkX2NvbnN0PFRPPjo6dHlwZTsKfTsKCnRlbXBsYXRlPHR5cGVuYW1lIEZST00sIHR5cGVuYW1lIFRPPgpzdHJ1Y3QgQ29weUNvbnN0IHsKCXVzaW5nIHR5cGUgPSB0eXBlbmFtZSBDb3B5Q29uc3RJbXBsPHR5cGVuYW1lIHN0ZDo6cmVtb3ZlX3JlZmVyZW5jZTxGUk9NPjo6dHlwZSwgVE8+Ojp0eXBlOwp9OwoKc3RydWN0IEZvbyB7CiAgaW50JiBiYXIoKSB7IHJldHVybiBiYXJJbXBsKCp0aGlzKTsgfQogIGNvbnN0IGludCYgYmFyKCkgY29uc3QgeyByZXR1cm4gYmFySW1wbCgqdGhpcyk7IH0KcHJpdmF0ZToKICB0ZW1wbGF0ZTx0eXBlbmFtZSBUSElTPgogIHN0YXRpYyBhdXRvIGJhckltcGwoVEhJUyYmIGluc3RhbmNlKSAtPiB0eXBlbmFtZSBDb3B5Q29uc3Q8VEhJUywgaW50Pjo6dHlwZSYgewogIAlyZXR1cm4gaW5zdGFuY2UueDsKICB9CiAgaW50IHggPSA1Owp9OwoKaW50IG1haW4oKSB7CglzdGF0aWNfYXNzZXJ0KGlzX3NhbWU8aW50JiwgZGVjbHR5cGUoZGVjbHZhbDxGb28+KCkuYmFyKCkpPjo6dmFsdWUsCgkJIk5vbi1jb25zdCBmb28uYmFyKCkgcmVzdWx0IG11c3QgeWllbGQgYSBub24tY29uc3QgcmVmZXJlbmNlIik7CglzdGF0aWNfYXNzZXJ0KGlzX3NhbWU8Y29uc3QgaW50JiwgZGVjbHR5cGUoZGVjbHZhbDxjb25zdCBGb28+KCkuYmFyKCkpPjo6dmFsdWUsCgkJIkNvbnN0IGZvby5iYXIoKSByZXN1bHQgbXVzdCB5aWVsZCBhIGNvbnN0IHJlZmVyZW5jZSIpOwoKCXJldHVybiAwOwp9