有没有一种方法可以让我使用 SFINAE 选择函数模板的重载,该函数模板在解析时会产生类型参数的其他等效替换?
根据要求,我制作了一个最小可复制示例(M.R.E.),可在此处完全获得:CPP.SH
但是,在这样做的过程中,我生成了一个示例,该示例并未反映我在实际代码中观察到的行为,因此我将尝试解释问题:
以下签名存在且相关:
#include <type_traits>
#include <iostream>
// Minimum reproducible example:
template <typename T>
class observable {
public:
observable() = default;
virtual ~observable() = default;
public:
T read() const {
std::cout << "Read " << m_value << ".\n";
return m_value;
}
void write(const T &value) {
std::cout << "Write " << value << ".\n";
m_value = value;
}
private:
T m_value;
};
template <typename T>
class iport : public virtual observable<T> {
public:
iport() = default;
virtual ~iport() = default;
// iport specific methods
};
template <typename T>
class oport : public virtual observable<T> {
public:
oport() = default;
virtual ~oport() = default;
// oport specific methods
};
template <typename T>
class ioport : public iport<T>, public oport<T> {
public:
ioport() = default;
virtual ~ioport() = default;
// ioport specific methods
};
// Overload 1
template<
typename value_u,
typename value_v,
typename = std::enable_if_t<
std::is_convertible_v<value_u, value_v>>>
void operator<<(observable<value_u> &sink, const value_v& src) {
// void observable<value_u>::write(const &value_u) is called
// on src directly
std::cout << "Using Overload 1\n";
sink.write(src);
}
// Overload 2
template<
typename value_u,
typename value_v,
typename = std::enable_if_t<
std::is_convertible_v<value_u, value_v>>>
void operator<<(observable<value_u> &sink, const observable<value_v>& src) {
// void observable<value_u>::write(const &value_u) is called
// after requesting a value via value_v observable<value_v>::read()
std::cout << "Using Overload 2\n";
sink.write(src.read());
}
int main(int, char*[]) {
iport<int> src;
ioport<int> mid;
oport<int> sink;
src << 2;
mid << src;
sink << mid;
}
在我的代码中,我正在调用(相当于)
sink << mid
,它无法编译并出现以下错误(解释):
[build] In instantiation of ‘void operator<<(observable<value_u>&, const value_v&) [with value_u = int; value_v = ioport<int>; <template-parameter-1-3> = void]’:
[build] error: cannot convert ‘const iport<int>’ to ‘const int&’
[build] 49 | sink.write(src);
[build] | ~~~~~~~~~~^~~~~
[build] note: initializing argument 1 of ‘void observable<T>::write(const T&) [with T = int]’
[build] 28 | void observable<T>::write(const T&value) {
在现实世界中,我的代码库试图将
ioport<int>
替换为 value_v
,这导致对 observable<int>::write(const int&)
的不兼容调用。
我不明白我给出的示例与链接中提供的 M.R.E 之间的差异。其他一切都是一样的,除了类型被重命名并且无关的实现被剥离。在重新考虑问题后,它的重点已经改变,尝试诊断错误替换发生的原因。