MasterPlanMan
MasterPlanMan

Reputation: 1032

C++ - Template function with volatile variable - can't call the template specialization

I'm trying to make a template function (in this case, in a class as a static method) and I can't seem to call the template specification I created. In other words, I expected the code to call the template specification I made and it doesn't.

class Atomic { 
public:     
    template <typename T>
    static T testAndSet(volatile T &t, T value) 
    {   
        ASSERT(false, "Unsupported type");
        return T();
    };

    template <long> 
    static long testAndSet(volatile long &t, long value )
    {
    #if defined(_PC)
        return InterlockedExchange(&t, value);  
    #else
        return __sync_lock_test_and_set(&t, value);
    #endif  
    };
};

Calling code:

volatile long counter = 0;      
long newValue = 4;
Atomic::testAndSet( counter, newValue);

The callstack shows:

sample.exe!Atomic::testAndSet(volatile long & t=0, long value=4)

I also tried it this way but it didn't work.

template <typename T, typename TT>
static TT testAndSet(T &t, TT value) { ... }

template <volatile long, long> 
static long testAndSet(volatile long &t, long value ) { ... }

or

template <typename T, typename TT>
static TT testAndSet(T t, TT value) { ... }

template <volatile long &, long> 
static long testAndSet(volatile long &t, long value ) { ... }

Same thing... so now I have to try and understand what's happenning instead or brute forcing my way into it. Until then, I'll watch Lavavej's core c++ videos.. =)

Upvotes: 2

Views: 2160

Answers (2)

Synxis
Synxis

Reputation: 9388

You can explicitely specialize template functions, but that's not the standard method for functions. And you cannot do it like you do : what you've wrote is two template functions, one with a type parameter, the other with a long non-type parameter.

// This defines a template function parameted with a long
//  vvvvvvvvvvvvvvv
    template <long> 
    static long testAndSet(volatile long &t, long value )

You need to specify explicitely the template parameter on the call site for this overload to be considered, that's why it was never taken by the compiler.

You need overloading here, change the previous function with this one (explicit specialization is not needed):

// Not a template function
    static long testAndSet(volatile long &t, long value)

Also, specializing a function template is done using the same syntax than for classes:

// Base case
template<typename T>
void function(T value);

// Explicit specialization (just an example)
template<>
void function<int>(int v, int a);

There are some differences between an explicit specialization and a simple overload, see this SO question for more details.

Upvotes: 2

jrok
jrok

Reputation: 55425

template <long> 
static long testAndSet(volatile long &t, long value )
{
#if defined(_PC)
    return InterlockedExchange(&t, value);  
#else
    return __sync_lock_test_and_set(&t, value);
#endif  
};

That's not a specialization as you seem to think. It's an overload with a (unnamed) non-type template parameter. It'll never be selected during overload resolution for the call you made because you need to explicitly specify the parameter, like this for example: testAndSet<42>(counter, newValue);.

The syntax you want is:

template <>  // <---
static long testAndSet<long>(volatile long &t, long value )
{                  // ^^^^^^
    //....
}

but at that point you could as well provide a normal overload.

You should always prefer overloading, because function template specializations can surprise you.

Upvotes: 1

Related Questions