gpt4 book ai didi

c++ - 删除未使用的重载会导致编译错误?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:51:49 25 4
gpt4 key购买 nike

我正在考虑删除一些未使用的重载,并触发了一个编译错误,编译器说这是一个模板替换错误。但我认为“替换失败不是错误”,无论如何,为什么删除过载会导致它?

简单的开始:

#include <string>

int ParseInt(const char *);
int ParseInt(std::string);

bool F(int(*)(const char *));

bool User() {
return F(ParseInt);
}

在这里,User() 使用解析例程的地址调用 F。一切都很好。 ParseInt 已重载,但只有一个重载与 F 的签名匹配。

输入 F 的模板化重载:

bool F(int(*)(const char *));

template <typename T>
struct MetaDeduce {
typedef typename T::X type;
};

template <typename T>
typename MetaDeduce<T>::type F(const T&);

现在有这个奇怪的 F 模板重载,但没关系,因为函数指针无论如何都没有名为 X 的成员。一切都编译好了,一切都很好。

直到......

#include <string>

int ParseInt(const char *);
// int ParseInt(std::string); // commenting this out caused a compiler error!

bool F(int(*)(const char *));

template <typename T>
struct MetaDeduce {
typedef typename T::X type;
};

template <typename T>
typename MetaDeduce<T>::type F(const T&);

bool User() {
return F(ParseInt);
}

从 godbolt ( http://goo.gl/2Yd04p ) 可以看出,这会产生一个奇怪的编译错误:

10 : error: type 'int (const char *)' cannot be used prior to '::'
because it has no members
typedef typename T::X type;
^
14 : note: in instantiation of template class 'MetaDeduce<int (const char *)>'
requested here
typename MetaDeduce<T>::type F(const T&);
^

什么鬼???看起来编译器在提示替换失败,但为什么以前不是问题呢?无论如何,我认为替换失败不是错误!怎么回事?

最佳答案

这是由两种语言属性之间的微妙相互作用引起的

  1. SFINAE 仅适用于直接上下文。你的MetaDeduce<T>没有在这样一个直接的上下文中定义,这使得 typename MetaDeduce<T>::type一个严重的错误。但 SFINAE 确实适用于 typename T::X ,并且使用它会编译你的代码,即使是 ParseInt(std::string)过载已注释掉。

    template <typename T>
    typename T::X F(const T&);

Live Example (请注意,您会收到链接器错误,因为您尚未定义函数)

  1. 所以如果 typename MetaDeduct<T>::type是罪魁祸首,为什么它与 ParseInt 的两个重载一起工作? ?好吧,考虑一下如果您只有模板 F 会发生什么和两个ParseInt秒。为了方便起见,给那个模板 F暂时忽略替换失败的 bool 返回类型。

    int ParseInt(const char *);
    int ParseInt(std::string);

    template <typename T>
    bool F(T const&);

    bool User() { return F(ParseInt); } // error, cannot deduce template argument

Live Example

有两个重载 ParseInt通话中没有额外信息 F(ParseInt) ,编译器无法推断出哪个版本的 ParseInt应该匹配模板参数 T .在此代码段的上下文中,这将导致硬错误(因为您将有一个空的重载集),但带有额外的非模板重载 F(int(*)(const char*))它不会(因为 ParseInt(const char*) 将匹配它)。请注意,由于此处的参数推导失败,如果返回类型为 typename MetaDeduce<T>::Type,则参数替换甚至不会发生。 .

实际上,ParseInt 的两个重载使您免受非直接上下文中的替换失败的影响。一旦拿走其中一个,参数推导就成功了,非立即替换失败导致硬错误。

这有点像闯红灯过马路,因为两辆迎面而来的卡车在撞到你之前就相撞而得救。只有一辆卡车,你会被撞到。

关于c++ - 删除未使用的重载会导致编译错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34931775/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com