【问题标题】:C++ - Template function with volatile variable - can't call the template specializationC++ - 具有可变变量的模板函数 - 无法调用模板特化
【发布时间】:2013-07-30 15:52:59
【问题描述】:

我正在尝试创建一个模板函数(在这种情况下,在一个类中作为静态方法),我似乎无法调用我创建的模板规范。换句话说,我希望代码调用我制作的模板规范,但它没有。

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  
    };
};

调用代码:

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

调用栈显示:

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

我也尝试过这种方法,但没有奏效。

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

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

或

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

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

同样的事情......所以现在我必须尝试了解正在发生的事情,或者强行进入它。在那之前,我会看 Lavavej 的核心 c++ 视频.. =)

【问题讨论】:

    标签: c++ templates static volatile template-specialization


    【解决方案1】:

    您可以明确地专门化模板函数,但这不是函数的标准方法。而且你不能像你那样做:你写的是两个模板函数,一个带有类型参数,另一个带有long非类型参数。

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

    您需要在调用站点上明确指定要考虑此重载的模板参数,这就是编译器从未采用它的原因。

    这里需要重载,把之前的函数改成这个(不需要显式特化):

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

    此外,函数模板的特化使用与类相同的语法来完成:

    // Base case
    template<typename T>
    void function(T value);
    
    // Explicit specialization (just an example)
    template<>
    void function<int>(int v, int a);
    

    显式特化和简单重载之间存在一些差异,请参阅this SO question 了解更多详细信息。

    【讨论】:

    • 你是对的!我一开始是这样做的,但是当我尝试为 GCC 编译它时进行了修改(无论如何这是另一个问题,所以我不会在这里问它(与非命名空间范围类 Atomic 中的显式专业化有关)。我想要专业化,因为我想专注于多种类型,但不是全部(Interlocked 支持不同的类型,具体取决于操作系统)。我会考虑切换到重载。Tks 很多!
    【解决方案2】:
    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  
    };
    

    这不像您想象的那样专业化。它是带有(未命名的)非类型模板参数的重载。在重载解析期间永远不会为您所做的调用选择它,因为您需要显式指定参数,例如:testAndSet&lt;42&gt;(counter, newValue);。

    你想要的语法是:

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

    但此时你也可以提供一个正常的重载。

    你应该总是更喜欢重载,因为函数模板特化can surprise you。

    【讨论】:

    • 你们都有相同的答案,我只能选择 1 作为答案,所以我会在答案上标记第一个(相差 1 分钟!)。非常感谢您的帮助!
    • @user1459231 没有汗水,伙计。 (但请注意我先回答了:D)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-15
    • 2016-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-07
    相关资源
    最近更新 更多