The following program yields a compilation error with clang
, though it passes on other compilers:
#include <utility>
struct foo
{
auto bar() -> decltype(0)
{
return 0;
}
using bar_type = decltype(std::declval<foo>().bar());
};
int main()
{
return 0;
}
clang
yields:
$ clang -std=c++11 clang_repro.cpp
clang_repro.cpp:10:48: error: member access into incomplete type 'foo'
using bar_type = decltype(std::declval<foo>().bar());
^
clang_repro.cpp:3:8: note: definition of 'foo' is not complete until the closing '}'
struct foo
^
1 error generated.
Is this program illegal, and if so, is there a correct way to define foo::bar_type
?
clang
details:
$ clang --version
Ubuntu clang version 3.5-1ubuntu1 (trunk) (based on LLVM 3.5)
Target: x86_64-pc-linux-gnu
Thread model: posix
Member Function Return Types. A public member function must never return a non-const reference or pointer to member data. A public member function must never return a non-const reference or pointer to data outside an object, unless the object shares the data with other objects.
Accessing data members and member functions: The data members and member functions of class can be accessed using the dot('. ') operator with the object.
Absolutely, this is possible. This is also quite common - for example, Factory Method pattern can be implemented within a single class, in which case member functions would be returning instances of the class of which they are members.
Explanation: The member functions can be called using only the dot operator or the arrow operator.
g++4.9 issues the same error
I'm not sure if this is an invalid code, because incomplete types are allowed for declval
, and expression in decltype
is not evaluated.
rightføld in his answer explained very good why this code is invalid.
You can use std::result_of:
using bar_type = std::result_of<decltype(&foo::bar)(foo)>::type;
Which is actually implemented like this:
using bar_type = decltype((std::declval<foo>().*std::declval<decltype(&foo::bar)>())());
The difference between this and the code in the question is that pointer-to-member operator (.*
) is used instead of member access operator (.
), and it doesn't require the type to be complete, which is demonstrated by this code:
#include <utility>
struct foo;
int main() {
int (foo::*pbar)();
using bar_type = decltype((std::declval<foo>().*pbar)());
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With