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