C ++编译器不检测类模板中的错误

时间:2015-09-03 11:24:07

标签: c++ templates c++11

考虑以下示例:

 public $validate = array(
          'email' => array(
            'notEmpty' => array(
                'rule' => 'notEmpty',
                'message' => 'This field cannot be left blank.',
                'last' => true,
            ),

            'checkMail' => array(
                'rule' => 'checkMail',
                'message' => 'Please provide a valid email address.',
                'last' => true,
            ),
            'isUnique' => array(
                'rule' => 'isUnique',
                'message' => 'Email address already in use.',
                'last' => true,
            ),
        ),
    );

      /**
         * check email format
         */
        function checkMail() {
            $email = $this->data['User']['email'];
            $dotInString = substr_count(strstr($email, '@'), '.');

            if ($dotInString > 2)
                return false;

            if ($dotInString > 1)
                $preg_match_string = "/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+(\.[a-zA-Z]{2,2})+(\.[a-zA-Z]{2,6})+$/";
            else
                $preg_match_string = "/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+(\.[a-zA-Z]{2,6})+$/";

            if (preg_match($preg_match_string, $email) > 0) {
                return true;
            } else {
                return false;
            }
        }

template <class T> class C { public: C(); C(C&& rhs); private: T m_data; }; template <class T> C<T>::C() : m_data(T()) { } template <class T> C<T>::C(C&& rhs) : m_data(rhs.data) { } int main() { C<int> i; } 包含错误,因为: m_data(rhs.data)没有名为C的成员。但是我尝试过的编译器(gcc 5.2,clang 3.5.1)都没有检测到该错误。

但是当我将以下行添加到data函数时,编译器会检测到错误:

main

为什么编译器在第一种情况下不会出错?

即使没有调用该特定函数,也可以发现C<int> j = std::move(i); 没有名为C的成员。

此外,当我将move构造函数的定义更改为以下内容时:

data

编译器在template <class T> C<T>::C(C&& rhs) : m_data(rhs.data) { data = 0; } 行上提供错误,但在data = 0;上没有。 所以函数被解析了。

4 个答案:

答案 0 :(得分:8)

在模板中检查错误有2次传递。

  • 一个用于非依赖代码
  • 一个用于依赖代码(在实例化时完成)

您的代码取决于模板,因此只有在实例化方法时才会检查它。

答案 1 :(得分:5)

您的模板格式不正确但错误不需要诊断(换句话说,允许编译器不提供错误消息并且可以执行任何想要的操作)。更确切地说,标准说

  

类似地,如果对象表达式的类型是当前实例化的类成员访问表达式中的id-expression不引用当前实例化的成员或未知专业化的成员,则程序生病 - 即使没有实例化包含成员访问表达式的模板;无需诊断。

在您的代码中C是当前实例化,rhs.data是类成员访问表达式,但不引用当前实例化的成员而不引用未知专业化的成员(这将是如果C具有依赖基类,即如果您要编写class C : T或类似的东西,则属于这种情况。

To read up on these rules, see this answer。同样值得一提的是,这种代码总是格式不正确(无需诊断),即使在没有我引用的这个添加规则的C ++ 03中也是如此。因为这段代码使得模板没有有效的实例化,对于所有可能类型的T.但是C ++ 03的现有规则相当广泛,并且这个C ++ 11的添加是一个简洁的测试,允许这种类型的代码安全拒绝。

答案 2 :(得分:4)

编译器不会尝试编译C(C&& rhs);,因为你没有调用它(在第一次尝试中)。 这在C ++中被称为零开销规则 - 你不会为你不能使用的东西付出代价。

当你尝试将其称为编译器而不是尝试编译函数并失败时。

答案 3 :(得分:3)

在这种情况下,编译器似乎无法弄清楚移动构造函数永远不会工作。 允许这样做,但不是必需的。

在一般情况下,很难检测到代码可以编译的T。如果C<int>C<float>失败,但适用于C<my_class>,则编译器不得抱怨(只要该函数不用于intfloat)。