Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

template specialization for std::atomic<double> &

I have this MCVE:

#include <stdio.h>
#include <atomic>

template<typename T> void assertVariableHasBeenSet( T, const char * );
template<>           void assertVariableHasBeenSet<std::atomic<double> &>
                                                        ( std::atomic<double> & myDouble, 
                                                          const char * variableName 
                                                        )
{
    printf( "Double:%s=%f\n", variableName,  myDouble.load() );
};

int main()
{
    std::atomic<double> myDoubleAtomic  {23.45};

    assertVariableHasBeenSet( myDoubleAtomic,   "myDoubleAtomic" );
}

I get this compiler error:

getType.cpp: In function ‘int main()’:
getType.cpp:14:61: error: use of deleted function ‘std::atomic<_Tp>::atomic(const std::atomic<_Tp>&) [with _Tp = double]’
  assertVariableHasBeenSet( myDoubleAtomic, "myDoubleAtomic" );
                                                             ^
In file included from getType.cpp:2:0:
/usr/local/include/c++/4.9.4/atomic:169:7: note: declared here
       atomic(const atomic&) = delete;
       ^
getType.cpp:4:27: error:   initializing argument 1 of ‘void assertVariableHasBeenSet(T, const char*) [with T = std::atomic<double>]’

How can I pass a std::atomic<double> reference to the specialized template? In a normal function it is possible.

like image 934
Peter VARGA Avatar asked Dec 16 '17 11:12

Peter VARGA


2 Answers

For this case, T will be deduced as std::atomic<double>, not std::atomic<double> &. Then the primary template will always be invoked instead of the specialization.

You can specify the template argument explicitly, e.g.

assertVariableHasBeenSet<std::atomic<double> &>(myDoubleAtomic, "myDoubleAtomic");

Or apply overloading.

template<typename T> void assertVariableHasBeenSet( T, const char * );

void assertVariableHasBeenSet( std::atomic<double> & myDouble, 
                               const char * variableName 
                             )
{
    printf( "Double:%s=%f\n", variableName,  myDouble.load() );
}
like image 185
songyuanyao Avatar answered Sep 25 '22 22:09

songyuanyao


Your issue is here:

template<typename T> void assertVariableHasBeenSet( T, const char * );

The primary template will be chosen because myDoubleAtomic is of type std::atomic<double>, not std::atomic<double> &.

The primary template tries to pass T by value, requiring a copy. std::atomic has a deleted copy constructor resulting in that error.

You should tell the compiler what type to use explicitly :

assertVariableHasBeenSet<std::atomic<double> &>(myDoubleAtomic,   "myDoubleAtomic" );
like image 28
Hatted Rooster Avatar answered Sep 24 '22 22:09

Hatted Rooster