【问题标题】:Why is volatile required with template argument in one case but not other?为什么在一种情况下模板参数需要 volatile 而在其他情况下不需要?
【发布时间】:2014-03-24 20:00:53
【问题描述】:

在 C++03 中,我使用 gcc v3.4.6 构建了以下代码,我不明白为什么调用 _setValueSafeFails() 会出现编译器错误,而调用类似的 _incrValueSafe() 则不会。

测试.h:

class Test
{
public:
  void test();

  template<typename T> void _incrValueSafe(T &value) {
    ++value;
  }

  template<typename T> void _setValueSafeFails(T &value, const T setVal) {
    value = setVal;
  }

  template<typename T> void _setValueSafeWorks(volatile T &value, const T setVal) {
    value = setVal;
  }

  volatile bool _testValue;

};

Test.cpp:

#include "Test.h"

void Test::test() {
  _incrValueSafe(_testValue);
  _setValueSafeFails(_testValue, true);
  _setValueSafeWorks(_testValue, true);
}

Test.cpp: In member function `void Test::test()':
Test.cpp:5: error: no matching function for call to `Test::_setValueSafeFails(volatile bool&, bool)'

_incrValueSafe() 不应该得到同样的错误,因为它的签名中也没有volatile?这两者如何区别对待,或者这只是一个编译器错误?

【问题讨论】:

  • (与您的问题无关,但您的变量名不应以_开头,那些是保留符号)
  • 我以为是保留的双下划线,但它们在一个类中,所以应该不是问题。

标签: c++ templates language-lawyer volatile


【解决方案1】:

正如其他人所解释的,将第一个参数绑定到 _testValue 意味着 Tvolatile bool,而将第二个参数绑定到 true 意味着T 仅仅是bool(没有volatile 修饰符)。这 clang 编译器给出了很好的诊断:

clang++ -o main  -std=c++1y -pedantic -Wall -stdlib=libc++ main.cpp -stdlib=libc++
main.cpp:26:5: error: no matching member function for call to '_setValueSafeFails'
    _setValueSafeFails(_testValue, true);
    ^~~~~~~~~~~~~~~~~~
main.cpp:12:35: note: candidate template ignored: deduced conflicting types for parameter 'T' ('volatile bool' vs. 'bool')
        template<typename T> void _setValueSafeFails(T &value, const T setVal) {
                                  ^
main.cpp:9:13: warning: incrementing expression of type bool is deprecated [-Wdeprecated-increment-bool]
            ++value;
            ^ ~~~~~
main.cpp:25:5: note: in instantiation of function template specialization 'Test::_incrValueSafe<volatile bool>' requested here
    _incrValueSafe(_testValue);
    ^
1 warning and 1 error generated.
make: *** [main] Error 1

关于前导下划线:我只是避免使用它们,部分是为了避免争论 什么是或不是严格合法的。我更喜欢流行的约定:前缀 带有m_ 的私有变量,并且不修饰任何私有函数名 特殊的方式。 (前导下划线是 Python 中私有成员的惯例, 但当然,C++ 是一种非常不同的语言。)为了记录,神圣的 标准规定如下:

17.6.4.3.2 Global names [global.names]


  1. 某些名称和函数签名集始终保留给 实现:

    — 每个名称都包含双下划线 __ 或以 下划线后跟大写字母 (2.12) 保留给 实现任何用途。

    - 每个以下划线开头的名称都保留给 在全局命名空间中用作名称的实现。

【讨论】:

    【解决方案2】:

    typename T 对于_incrValueSafevolatile bool

    【讨论】:

      【解决方案3】:

      因为

      template<typename T> void _setValueSafeFails(T &value, const T setVal) {
          value = setVal;
      }
      

      将被实例化为:

      void _setValueSafeFails(volatile bool &value, const volatile bool setVal)
      

      【讨论】:

        【解决方案4】:

        volatile bool和bool类型是不同的类型,导致_setValueSafeFails不匹配。

        你可以这样做:

        class Test
        {
        public:
          void test();
          template<typename T, typename U> void _setValueSafeA(T &value, const U setVal) {
            value = setVal;
          }
          template<typename T> void _setValueSafeB(T &value, const T& setVal) {
            value = setVal;
          }
        
          volatile bool _testValue;
        
        };
        
        void Test::test() {
          volatile bool true_value = true;
          _setValueSafeA(_testValue, true);
          _setValueSafeB(_testValue, true_value);
        }
        

        【讨论】:

          猜你喜欢
          • 2018-09-08
          • 1970-01-01
          • 2017-07-15
          • 2011-03-27
          • 2016-08-08
          • 1970-01-01
          • 2016-07-17
          • 1970-01-01
          • 2018-06-24
          相关资源
          最近更新 更多