考虑以下示例:
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;
上没有。
所以函数被解析了。
答案 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>
,则编译器不得抱怨(只要该函数不用于int
或float
)。