Drax
Drax

Reputation: 13288

constexpr : literal class type copy behavior

let's take the following code:

class   const_int                                                                                                                                                                                                    
{                                                                                                                                                                                                                    
public:                                                                                                                                                                                                              
  constexpr const_int(int data) : data_(data) {}                                                                                                                                                                     
  constexpr const_int(const const_int &) = default;                                                                                                                                                                  
  constexpr const_int(const_int &&) = default;                                                                                                                                                                       

private:                                                                                                                                                                                                             
  int   data_;                                                                                                                                                                                                       
};

class   test                                                                                                                                                                                                         
{                                                                                                                                                                                                                    
public:                                                                                                                                                                                                              

  constexpr static const const_int      USER = 42;                                                                                                                                                                

  constexpr static const double         NATIVE = 4.2;                                                                                                                                                                
};

// constexpr const const_int test::USER;

void    pass_by_copie(double)                                                                                                                                                                                        
{                                                                                                                                                                                                                    
}

void    pass_by_copie(const_int)                                                                                                                                                                                     
{                                                                                                                                                                                                                    
}

void    pass_by_const_ref(const const_int&)                                                                                                                                                                          
{                                                                                                                                                                                                                    
}

void    pass_by_rvalue_ref(const_int&&)                                                                                                                                                                              
{                                                                                                                                                                                                                    
}

int     main(void)                                                                                                                                                                                                   
{                                                                                                                                                                                                                    

  pass_by_copie(test::NATIVE);                                                                                                                                                                                       

  pass_by_copie(test::USER);                                                                                                                                                                                         

  pass_by_const_ref(test::USER);                                                                                                                                                                                         

  pass_by_rvalue_ref(const_int(test::USER));                                                                                                                                                                         

  return (0);                                                                                                                                                                                                        
}

Both of the following lines :

pass_by_copie(test::USER);
pass_by_const_ref(test::USER);

produce the following error under g++ 4.7 :

undefined reference to `test::USER'

I am aware of the fact that there is no instance of test::USER. (the line is commented on purpose)


I have two questions :

  1. Why is an explicit instance of test::USER needed while no explicit instance of test::NATIVE is needed to call the function pass_by_copie?

  2. Why can i call pass_by_rvalue_ref by explicity creating a temporary copie from test::USER while the compiler is unable (or doesn't want) to create the same copie implicitly himself when calling pass_by_copie with test::USER ?

Thank you

Upvotes: 3

Views: 353

Answers (2)

Ben Voigt
Ben Voigt

Reputation: 283803

From section 3.2 of C++11:

A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression and the lvalue-to-rvalue conversion is immediately applied.

and

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program

So the definition is required because test::USER is odr-used, and apparently it is odr-used because it does not immediately undergo lvalue-to-rvalue conversion. That surprises me, the call to pass_by_copie looks like it performs an lvalue-to-rvalue conversion.

Upvotes: 2

Lily Ballard
Lily Ballard

Reputation: 185821

Clang 4.1 gives me this error:

Undefined symbols for architecture x86_64:
  "test::USER", referenced from:
      _main in Untitled-gXrry2.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I'm assuming what's going on here is test::NATIVE can be simply replaced with the value 4.2 where it's used, and doesn't actually require a symbol. But test::USER, being an instance of a class rather than a scalar, does require a symbol so that all references to test::USER refer to the same object. Given this, you actually do need the explicit instance.

Upvotes: 1

Related Questions