【问题标题】:template specialization for std::atomic<double> &std::atomic<double> & 的模板特化
【发布时间】:2017-12-16 11:23:01
【问题描述】:

我有这个 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" );
}

我得到这个编译器错误:

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>]’

如何将std::atomic&lt;double&gt; 引用传递给专用模板? 在正常功能中是可能的。

【问题讨论】:

    标签: c++ c++11 templates template-specialization


    【解决方案1】:

    对于这种情况,T 将被推断为std::atomic&lt;double&gt;,而不是std::atomic&lt;double&gt; &amp;。然后将始终调用主模板而不是特化。

    您可以显式指定模板参数,例如

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

    或者应用重载。

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

    【讨论】:

    • 我现在明白了!我使用重载模板进行了您的第二次编辑!我不想指定 [e.q.给编译器提示]使用什么! +1
    • @AlBundy 是的,函数模板重载在大多数情况下非常好用,所以不要忘记它。
    【解决方案2】:

    您的问题在这里:

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

    将选择主模板,因为 myDoubleAtomic 的类型为 std::atomic&lt;double&gt;,而不是 std::atomic&lt;double&gt; &amp;

    主模板尝试按值传递T,需要一个副本。 std::atomic 有一个已删除的复制构造函数导致该错误。

    你应该明确告诉编译器使用什么类型:

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

    【讨论】:

    • 是的,Rick,你的 你应该告诉编译器要显式使用什么类型 照亮了这种情况。我更喜欢模板重载! +1 谢谢
    【解决方案3】:

    首先发生的是重载决议。在重载解析期间,类型T 被推断为std::atomic&lt;double&gt;。接下来确定适当的专业化。没有专门的版本,使用的是主模板。 std::atomic&lt;double&gt;&amp; 的特化永远不会通过推理找到。

    有两种方法可以解决这个问题(我不认为明确指定类型是一种解决方案):

    1. 声明主模板采用转发引用T&amp;&amp;,因为这会将T 推导出为std::atomic&lt;double&gt;&amp;
    2. 使用重载代替模板特化,即删除函数名称后的template&lt;&gt;&lt;std::atomic&lt;double&gt;&amp;&gt;

    【讨论】:

      猜你喜欢
      • 2020-12-15
      • 1970-01-01
      • 1970-01-01
      • 2021-06-08
      • 2021-07-15
      • 2016-11-07
      • 1970-01-01
      • 2014-06-13
      • 1970-01-01
      相关资源
      最近更新 更多