我试图理解为什么这段代码没有按预期工作
#include <cstdio>
#include <vector>
#include <type_traits>
using namespace std;
struct Foo {
};
template<typename T, typename = void>
void compare(const T&a, const T&b) {
cout << "default" << endl;
}
template<typename T, std::enable_if_t<std::is_same<T, Foo>::value>>
void compare(const T& a, const T &b) {
cout << "In object" << endl;
}
int main(int argc, char const *argv[]) {
compare(1, 2);
{
vector<int> a, b;
compare(a, b);
}
{
Foo a, b;
compare(a, b);
}
return 0;
}
在所有情况下都会打印“默认”。对于最后一种情况,我希望调用第二个函数。
答案 0 :(得分:3)
你没有专门化inline static int counter{1};
(无论如何都不可能部分地专门化一个功能模板)。而是提供过载。
超载总是非法的:
compare
。enable_if_t
的非类型模板参数。所以它永远不会被调用,因为SFINAE放弃了它而支持顶部始终有效的过载。
专业化通常是功能模板的错误答案。相反,你应该委托一个类模板,将在真正的专业化时按预期行事:
void
答案 1 :(得分:2)
使用类模板是一种有效的解决方案,这是通过标记调度实现此结果的另一种方法:
template <class T>
void compare(const T & l, const T & r, std::true_type)
{
cout << "In object" << endl;
}
template <class T>
void compare(const T & l, const T & r, std::false_type)
{
cout << "default" << endl;
}
template <class T>
void compare(const T & l, const T & r)
{
compare(l, r, std::is_same<T, Foo>{});
}
答案 2 :(得分:1)
推迟使用专门的函数对象可以在参数类型和/或它们是rvalues还是lvalues方面提供很大的灵活性。
#include <iostream>
#include <vector>
#include <type_traits>
using namespace std;
// general case
template<class T>
struct compare_impl
{
template<class U, class V>
auto operator()(U&& a, V&& b) const {
cout << "default" << endl;
}
};
// compare interface
template<class T, class U>
auto compare(T && a, U && b)
{
using ctype = std::common_type_t<std::decay_t<T>, std::decay_t<U>>;
auto impl = compare_impl<ctype>();
return impl(a, b);
}
// now specialise for objects for which we want custom behaviour
struct Foo {
};
template<>
struct compare_impl<Foo>
{
template<class U, class V>
auto operator()(U&& a, V&& b) const {
cout << "In object" << endl;
}
};
int main(int argc, char const *argv[]) {
compare(1, 2);
{
vector<int> a, b;
compare(a, b);
}
{
Foo a, b;
compare(a, b);
}
return 0;
}