为什么C++在找到时没有找到bool运算符!运营商的范围?

gct*_*gct 1 c++ templates c++11

在解析器组合库上工作,这个例子来源于此,但显然有些名称已被更改以保护无辜者:

#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;
    }    
}
Run Code Online (Sandbox Code Playgroud)

我有一个模板操作员!应该只在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;
                    ^
Run Code Online (Sandbox Code Playgroud)

Rak*_*111 5

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

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

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