有没有办法确保除非所有其他重载都失败,否则不会选择模板重载,而不使用enable_if?
Int应该由long重载处理,但它由模板重载处理,编译器不喜欢它。
class SetProxy {
public:
void operator=(const TemplateString& value) {
dict_.SetValue(variable_, value);
}
template<class T>
void operator=(const T& value) {
dict_.SetValue(variable_, TemplateString(value.data(), value.size()));
}
void operator=(long value) {
dict_.SetIntValue(variable_, value);
}
}
答案 0 :(得分:5)
为什么int
超载会处理long
?它们的类型不同,T = int
的模板与int
完全匹配,而long
不是完美匹配。
您能否提供有关您尝试解决的潜在问题的更多信息?
答案 1 :(得分:0)
问题中代码的问题是,如果可转换为long
或TemplateString
的参数被传递,则模板是最佳匹配:模板在调用时不需要进行转换其他功能将涉及转换。
即使不使用std::enable_if
,也可以实现所需的行为,尽管我认为禁止使用std::enable_if
是一个弥补的要求:即使您不能使用C ++ 2011或提升,实现std::enable_if
非常简单。实现一些所需的类型特征有点困难但可行。有效地限制其使用意味着您需要以或多或少的方式实现基本相同的逻辑,而不是说它实际上做了什么。例如,此代码不使用std::enable_if
或SFINAE,但实际创建了一个额外的对象,如果使用了SFINAE则不需要该对象:
#include <iostream>
#include <string>
class SetProxy {
template <typename F>
struct helper {
helper(F const& v): value_(v) {}
F const& value_;
};
template<typename F>
void aux(helper<F> value, ...) {
std::cout << "template " << value.value_ << "\n";
}
template<typename F>
void aux(long value, int) {
std::cout << "long: " << value << "\n";
}
template<typename F>
void aux(std::string const& value, int) {
std::cout << "string: " << value << "\n";
}
public:
template<typename T>
void operator=(const T& value) {
this->aux<T>(value, 0);
}
};
struct foo {};
std::ostream& operator<< (std::ostream& out, foo const&) {
return out << "foo";
}
int main()
{
SetProxy p;
p = 17l;
p = 17;
p = foo();
p = "hello";
p = std::string("hello");
}
它不使用原始问题中的类型,因为我没有它们可访问,我不想输入与实际问题无关的内容。请注意,这实际上包含std::is_convertible
实现的重要部分。在内部,有必要转发到另一个模板,因为赋值运算符不能具有可变参数列表:因为从int
到helper<int>
存在可行的转换,如果没有任何内容,则会有歧义除了区分类型之外,还使用变量参数列表使模板版本更糟糕。
仅供参考,我认为这是使用std::enable_if
的更具可读性的版本:
class SetProxy {
public:
template <typename T>
typename std::enable_if<!std::is_convertible<T, long>::value
&& !std::is_convertible<T, std::string>::value, void>::type
operator= (T const& value) {
std::cout << "template: " << value << "\n";
}
void operator= (long value) {
std::cout << "long: " << value << "\n";
}
void operator= (std::string value) {
std::cout << "std::string: '" << value << "'\n";
}
};
答案 2 :(得分:0)
int匹配模板版本并不意外。模板参数匹配将获得const int&
的正匹配,并将其传递给重载决策。 const int&
比int
更适合long
。如果你想避免为int类型调用模板版本,那么我建议你为int添加一个显式重载。