我正在尝试创建一个类型化比较函数,为不同类型进行一些自定义比较。
function Test() {
this.myTest = "Test";
}
Test.prototype.toString = function testToString() {
return this.myTest;
};
var test = new Test();
console.log(test.toString());
这里我有 #include <type_traits>
template <typename T>
bool typedCompare(const T& lhs, const T& rhs)
{
return lhs == rhs; // default case, use ==
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, bool>::type
typedCompare(const T& lhs, const T& rhs)
{
return (lhs - rhs) < 1e-10;
}
int main()
{
typedCompare(1, 1);
typedCompare(1.0, 1.0);
return 0;
}
的特殊版本,可以将差异与少量进行比较(请忽略我没有使用double
这一事实)。我还有一些其他自定义类型需要进行一些特殊比较,而且出于某种原因我无法更改std::abs()
运算符。
此外,我仍然想要一个&#34;全能&#34;使用==
运算符的样式函数。我的问题是,在尝试编译此代码片段时,编译器抱怨==
不明确,它可以选择提供的两个函数中的任何一个。
为什么呢?我怎么能解决这个问题?
感谢。
答案 0 :(得分:6)
为什么?
简而言之,您使用的SFINAE不正确,因此当您为双打调用typedCompare
时,这两个功能模板都有效。
我该如何解决这个问题?
在这种特殊情况下,修复SFINAE以使其正常工作:
template <typename T>
typename std::enable_if<!std::is_floating_point<T>::value, bool>::type
typedCompare(const T& lhs, const T& rhs)
{
return lhs == rhs; // default case, use ==
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, bool>::type
typedCompare(const T& lhs, const T& rhs)
{
return (lhs - rhs) < 1e-10;
}
请注意,此解决方案在许多类型的自定义方面不是那么好。另一种方法是使用标签调度:
struct floating_point_tag {};
// other tags
template <typename T>
bool typedCompare(const T& lhs, const T& rhs, floating_point_tag) {
return (lhs - rhs) < 1e-10;
}
// implementations for other tags
template <typename T>
bool typedCompare(const T& lhs, const T& rhs) {
if (std::is_floating_point<T>::value) {
return typedCompare(lhs, rhs, floating_point_tag{});
}
// other checks here
return lhs == rhs;
}
最后,使用C ++ 17,您可以使用if constexpr
:
template <typename T>
bool typedCompare(const T& lhs, const T& rhs) {
if constexpr (std::is_floating_point<T>::value) {
return (lhs - rhs) < 1e-10;
} else { // add other if-else here
return lhs == rhs;
}
}
答案 1 :(得分:2)
您的问题中的代码问题是,当浮点typedCompare()
启用SFINAE时,会与通用版本冲突,因为编译器不能优先于另一个版本。
要解决这个问题,我建议您采用另一种方式,基于模板部分特化(仅适用于结构和类,因此需要帮助struct
)
如果您按如下方式定义帮助struct
template <typename T, typename = void>
struct typedCompareHelper
{
static constexpr bool func (T const & lhs, T const & rhs)
{ return lhs == rhs; } // default case, use ==
};
template <typename T>
struct typedCompareHelper<T,
typename std::enable_if<std::is_floating_point<T>::value>::type>
{
static constexpr bool func (T const & lhs, T const & rhs)
{ return (lhs - rhs) < 1e-10; }
};
您可以避免歧义问题,因为typedCompareHelper
专业化更专业化的泛型问题。
您可以简单地为不同的特殊情况添加更多特化,只关注避免碰撞(适用于同一类型的同一级别的不同特化)。
您的typedCompare()
变得简单
template <typename T>
bool typedCompare (T const & lhs, T const & rhs)
{ return typedCompareHelper<T>::func(lhs, rhs); }
答案 2 :(得分:1)
我喜欢@ max66的解决方案和辅助模板以及@Edgar Rokyan的多种解决方案。
这是另一种可以使用辅助模板函数用于所需内容的方法。
#include <type_traits>
#include <iostream>
#include <string>
// elipsis version is at the bottom of the overload resolution priority.
// it will only be used if nothing else matches the overload.
void typeCompare_specialized(...)
{
std::cout << "SHOULD NEVER BE CALLED!!!\n";
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, bool>::type
typeCompare_specialized(const T& lhs, const T& rhs)
{
std::cout << "floating-point version\n";
return (lhs - rhs) < 1e-10;
}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
typeCompare_specialized(const T& lhs, const T& rhs)
{
std::cout << "integral version\n";
return lhs == rhs;
}
template <typename T>
auto typedCompare(const T& lhs, const T& rhs)
-> typename std::enable_if<std::is_same<bool,decltype(typeCompare_specialized(lhs, rhs))>::value,bool>::type
{
return typeCompare_specialized(lhs, rhs);
}
template <typename T>
auto typedCompare(const T& lhs, const T& rhs)
-> typename std::enable_if<!std::is_same<bool,decltype(typeCompare_specialized(lhs, rhs))>::value,bool>::type
{
std::cout << "catch-all version\n";
return lhs == rhs;
}
int main()
{
typedCompare(1, 1);
typedCompare(1.0, 1.0);
typedCompare(std::string("hello"), std::string("there"));
return 0;
}
运行上述程序将产生以下输出:
integral version
floating-point version
catch-all version
同样,我更愿意使用前面提到的答案之一。我把这种可能性包括在内。
我还想补充一点,你应该确保你的typeCompare_specialized()
模板版本不应该有任何重叠,否则你可能会收到一个编译器错误声明有多个候选重载要使用。