question

JohnEmmas-0498 avatar image
0 Votes"
JohnEmmas-0498 asked ·

Can't assign the address of std::list::unique()


According to MSDN 'std::list::unique()' returns type void - so why doesn't the following C++ code compile in VS2019?

Can anyone see a problem with the code? Or suggests a fix / workaround?

 #include <list>
    
 using LT = std::list<int>;
    
 using func_void_t = void(LT::*)();
 using func_ref_t = LT::reference(LT::*)();
 using func_iter_t = LT::iterator(LT::*)();
    
 int main (int argc, char *argv[])
 {
 // Non-overloaded members
   func_void_t f1 = &LT::reverse;     // Succeeds
   func_void_t f2 = &LT::clear;       // Succeeds
   func_void_t f3 = &LT::sort;        // Succeeds
   func_void_t f4 = &LT::pop_front;   // Succeeds
    
 // Members with overloads
   func_ref_t f6  = &LT::front;       // Succeeds
   func_iter_t f7 = &LT::end;         // Succeeds
   func_void_t f5 = &LT::unique;      // FAILS (error C2440)
    
   return 0;
 }
c++
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Viorel-1 avatar image
0 Votes"
Viorel-1 answered ·

Try this workaround:

 . . .
 if constexpr( false ) LT( ).unique( );
 func_void_t f5 = &LT::unique;
 . . .

or

 . . .
 using unused = decltype( std::declval<LT>( ).unique( ) );
 func_void_t f5 = &LT::unique;
 . . .
·
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

JohnEmmas-0498 avatar image
0 Votes"
JohnEmmas-0498 answered ·

Wow! I'd scratched my head for over a week with this but I tried your solution #2 and it seems to fix the problem - many thanks !!

It'd be really great if you could explain a bit how that solution works....

· 2 ·
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.


It seems that the compiler does not work well yet with new kind of functions that return auto. Your code works with sort because it is ‘void sort()’, but fails in case of ‘auto uniqie()’. The workarounds try referencing the functions using some alternative ways. (The second workaround gets the type of parameter-less unique member function, applied to an imaginary value introduced by declval). This probably “warms up” the compiler, helping it to recognise the auto functions.

A shorter example that demonstrates the problem:

 template<typename T>
 class List
 {
 public:
    auto unique( ) { return unique( 0 ); }
    
    template<typename A>
    void unique( A x ) { }
 };
    
 void main( )
 {
    void( List<int>:: * p )( ) = &List<int>::unique; // Error C2440
 }

Maybe you can report the issue to https://developercommunity.visualstudio.com.

0 Votes 0 ·

Yes, definitely report it, the latest GCC & clang (tested on compiler explorer) don't have a problem with your original code.
Please post a link back here to your bug report too.

0 Votes 0 ·
IgorTandetnik-1300 avatar image
0 Votes"
IgorTandetnik-1300 answered ·

First, std::list::unique returns void in C++17 and earlier, but size_t in C++20: source. Even if you get your program to compile now, it will likely start to break soon.

Second, it is generally not portable to take an address of a member function of a standard library class:

[member.functions]/2 For a non-virtual member function described in the C++ standard library, an implementation may declare a different set of member function signatures, provided that any call to the member function that would select an overload from the set of declarations described in this document behaves as if that overload were selected. [Note: For instance, an implementation may add parameters with default values, or replace a member function with default arguments with two or more member functions with equivalent behavior, or add additional signatures for a member function name. —end note]

So your whole design relies on implementation details.

What is the original problem you are trying to solve, for which you want to use pointers-to-member? There may be other, portable ways to solve it.

·
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

JohnEmmas-0498 avatar image
0 Votes"
JohnEmmas-0498 answered ·

Many thanks guys - I appreciate all the help. There's quite a long discussion about this, over on CodeGuru


In a nutshell, I'm trying to build some code for a library we use here (the library's called Lua). It seems to produce a "customized" version of some general template stuff, like list and vector etc (i.e. it only allows some of the available functions - whereas some extra ones can be added)

In post #14, 2kaud (the guy who's been helping me) mentions that he'll be passing this on to the VS development team so hopefully they'll become aware of it soon.

·
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.