1

After migrating from MS Visual Studio 2008 to MS Visual Studio 2017 and compiling using v140 toolset, I got a problem with defining whether a specific member variable is present in class. In my case it not a simple variable but a static const reference. It worked fine in under 2008.

Here is an extract from my code which doesn't compile

#include <iostream>
#include <string>


struct ActivityEntry
{
    static const std::string& AutoIncrementName;
};

template< typename Entry >
struct AutoIncrementNameSelect
{    
    template< const std::string* >
    struct TestHasMember;

    template< typename T >
    static int f( TestHasMember< &T::AutoIncrementName >*, void* );

    template< typename T >
    static char f( TestHasMember< &T::AutoIncrementName >*, ... );

    enum { UseAutoIncrement = ( sizeof( f< Entry >( 0, 0 ) ) == sizeof( int ) ) };
};

std::string s("aaa");
//initialize the reference
const std::string & ActivityEntry::AutoIncrementName(s);

int main()
{
    std::cout<<"Use autoinc:"<< AutoIncrementNameSelect<ActivityEntry>::UseAutoIncrement;

    return 0;
}

In my original code the error is: "pointer to reference member is illegal" with reference to:

enum { UseAutoIncrement = ( sizeof( f< Entry >( 0, 0 ) ) == sizeof( int ) ) };

Here, the error is

 error: '& ActivityEntry::AutoIncrementName' is not a valid template argument for 'const string* {aka const std::basic_string*}' because it is not the address of a variable
1
  • Using 'decltype' solves the problem, thanks @A. A for pointing it out
    – K.S
    Commented Dec 14, 2017 at 10:20

1 Answer 1

1

You can modify the AutoIncrementName to be a std::string object, not a reference, so that you could take its address. Or change the two f() methods like this:

template< typename T >
static int f( decltype(&T::AutoIncrementName)*, void* );

template< typename T >
static char f( decltype(&T::AutoIncrementName)*, ... );

Non-type template arguments have some limitations [temp.arg.nontype]/2:

2 A template-argument for a non-type template-parameter shall be a converted constant expression (8.20) of the type of the template-parameter. For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):

—(2.1) a subobject (4.5),

—(2.2) a temporary object (15.2),

—(2.3) a string literal (5.13.5),

—(2.4) the result of a typeid expression (8.2.8), or

—(2.5) a predefined __func__ variable (11.4.1).

Not the answer you're looking for? Browse other questions tagged or ask your own question.