首页 > 解决方案 > 为什么 C++ 在有 ! 时找不到布尔运算符 范围内的运算符?

问题描述

处理一个解析器组合库,这个例子是从这个库派生出来的,尽管很明显一些名字已经被改变以保护无辜者:

#include <string>
#include <stdio.h>

using namespace std;

template <typename T> struct only_string;
template <>           struct only_string<string> {};

struct another_type {
    explicit operator bool() const { return true; }
};


// only substitute if T is string
template <typename T>
bool operator !(T) {
    only_string<T> a;
    return true;
}


int main() {
    another_type a;
    if (!a) {
        return 1;
    } else {
        return 0;
    }    
}

我有一个模板运算符!仅当 T 是字符串时才应替换,而另一种类型上有 bool 运算符。如果我尝试调用 !a,它会首先找到操作员,但无法替换并放弃。谁能解释这种行为以及如何纠正它?

这是 g++ 5.4.0 的输出

> g++ -std=c++11 test.cc -o test

test.cc: In instantiation of ‘bool operator!(T) [with T = another_type]’:
test.cc:24:10:   required from here
test.cc:17:20: error: ‘only_string<another_type> a’ has incomplete type
     only_string<T> a;
                    ^

标签: c++c++11templates

解决方案


是的,编译器“放弃”了,因为它认为 ! 运营商是最好的匹配。如果您真的希望编译器忽略该重载,则需要使用一种称为 SFINAE 的技术。

template <typename T,
        std::enable_if_t<std::is_same_v<T, std::string>>* = nullptr>
bool operator !(T) {
    return true;
}

这样,如果编译器尝试选择此函数,它将无法将参数替换为签名并忽略它。这不会发生在函数体中,这就是您的版本失败的原因。


推荐阅读