SFINAE 错误
Error with SFINAE
为什么下面的代码会出错?我认为编译器只是在这里选择适当的重载?
#include <iostream>
using std::cout;
using std::endl;
template <typename ToCheckFor>
struct InterfaceCheck {
// used by the constexpr function, the function will pass in a pointer to
// a type with the required types
template <typename _ToCheckFor, void (_ToCheckFor::*) ()>
struct InterfaceCheckImplTag {};
// used to check for the presence of a function print()
// template <typename T>
// static constexpr bool function(__attribute__((unused)) void* ptr) {}
template <typename T>
static constexpr bool function(__attribute__((unused)) void* ptr) {
return false;
}
template <typename T>
static constexpr bool function (__attribute__((unused))
InterfaceCheckImplTag<T, &T::print>* ptr) {
return true;
}
constexpr static const bool value = function<ToCheckFor>(nullptr);
};
struct Something {
void print() { cout << "Something::print()" << endl; }
};
int main() {
cout << InterfaceCheck<Something>::value << endl;
return 0;
}
为什么用省略号替换 void*
参数会使代码按预期工作?所以下面的代码按预期工作
#include <iostream>
using std::cout;
using std::endl;
template <typename ToCheckFor>
struct InterfaceCheck {
// used by the constexpr function, the function will pass in a pointer to
// a type with the required types
template <typename _ToCheckFor, void (_ToCheckFor::*) ()>
struct InterfaceCheckImplTag {};
// used to check for the presence of a function print()
// template <typename T>
// static constexpr bool function(__attribute__((unused)) void* ptr) {}
template <typename T>
static constexpr bool function(...) {
return false;
}
template <typename T>
static constexpr bool function (__attribute__((unused))
InterfaceCheckImplTag<T, &T::print>* ptr) {
return true;
}
constexpr static const bool value = function<ToCheckFor>(nullptr);
};
struct Something {
void print() { cout << "Something::print()" << endl; }
};
int main() {
cout << InterfaceCheck<Something>::value << endl;
return 0;
}
Why does the following code cause an error?
function
重载有两个可行的选择。两者都涉及从提供的参数进行转换,并且两种转换都不比另一种更好:
error: call to 'function' is ambiguous
constexpr static const bool value = function<ToCheckFor>(nullptr);
^~~~~~~~~~~~~~~~~~~~
test.cpp:36:13: note: in instantiation of template class 'InterfaceCheck<Something>' requested here
cout << InterfaceCheck<Something>::value << endl;
^
test.cpp:17:27: note: candidate function [with T = Something]
static constexpr bool function(__attribute__((unused)) void* ptr) {
^
test.cpp:21:27: note: candidate function [with T = Something]
static constexpr bool function (__attribute__((unused))
使用 function(...)
修复是有效的,因为从任何东西到 ...
的转换总是 "worse" 匹配而不是其他任何东西(但仍然合法)。一旦你知道了,这是一个绝妙的技巧。
来自 13.3.3.2 Ranking implicit conversion sequences [over.ics.rank]:
When comparing the basic forms of implicit conversion sequences (as defined in 13.3.3.1)
a standard conversion sequence (13.3.3.1.1) is a better conversion sequence than a user-defined conversion sequence or an ellipsis
conversion sequence, and
a user-defined conversion sequence (13.3.3.1.2) is a better conversion sequence than an ellipsis conversion sequence
(13.3.3.1.3).
历史
我是从 Modern C++ Design 的第 2.7 节开始学习这项技术的。我不确定这是不是它的发明地。但这不是一个糟糕的猜测。这本书已经15年了,还是很好读。
为什么下面的代码会出错?我认为编译器只是在这里选择适当的重载?
#include <iostream>
using std::cout;
using std::endl;
template <typename ToCheckFor>
struct InterfaceCheck {
// used by the constexpr function, the function will pass in a pointer to
// a type with the required types
template <typename _ToCheckFor, void (_ToCheckFor::*) ()>
struct InterfaceCheckImplTag {};
// used to check for the presence of a function print()
// template <typename T>
// static constexpr bool function(__attribute__((unused)) void* ptr) {}
template <typename T>
static constexpr bool function(__attribute__((unused)) void* ptr) {
return false;
}
template <typename T>
static constexpr bool function (__attribute__((unused))
InterfaceCheckImplTag<T, &T::print>* ptr) {
return true;
}
constexpr static const bool value = function<ToCheckFor>(nullptr);
};
struct Something {
void print() { cout << "Something::print()" << endl; }
};
int main() {
cout << InterfaceCheck<Something>::value << endl;
return 0;
}
为什么用省略号替换 void*
参数会使代码按预期工作?所以下面的代码按预期工作
#include <iostream>
using std::cout;
using std::endl;
template <typename ToCheckFor>
struct InterfaceCheck {
// used by the constexpr function, the function will pass in a pointer to
// a type with the required types
template <typename _ToCheckFor, void (_ToCheckFor::*) ()>
struct InterfaceCheckImplTag {};
// used to check for the presence of a function print()
// template <typename T>
// static constexpr bool function(__attribute__((unused)) void* ptr) {}
template <typename T>
static constexpr bool function(...) {
return false;
}
template <typename T>
static constexpr bool function (__attribute__((unused))
InterfaceCheckImplTag<T, &T::print>* ptr) {
return true;
}
constexpr static const bool value = function<ToCheckFor>(nullptr);
};
struct Something {
void print() { cout << "Something::print()" << endl; }
};
int main() {
cout << InterfaceCheck<Something>::value << endl;
return 0;
}
Why does the following code cause an error?
function
重载有两个可行的选择。两者都涉及从提供的参数进行转换,并且两种转换都不比另一种更好:
error: call to 'function' is ambiguous
constexpr static const bool value = function<ToCheckFor>(nullptr);
^~~~~~~~~~~~~~~~~~~~
test.cpp:36:13: note: in instantiation of template class 'InterfaceCheck<Something>' requested here
cout << InterfaceCheck<Something>::value << endl;
^
test.cpp:17:27: note: candidate function [with T = Something]
static constexpr bool function(__attribute__((unused)) void* ptr) {
^
test.cpp:21:27: note: candidate function [with T = Something]
static constexpr bool function (__attribute__((unused))
使用 function(...)
修复是有效的,因为从任何东西到 ...
的转换总是 "worse" 匹配而不是其他任何东西(但仍然合法)。一旦你知道了,这是一个绝妙的技巧。
来自 13.3.3.2 Ranking implicit conversion sequences [over.ics.rank]:
When comparing the basic forms of implicit conversion sequences (as defined in 13.3.3.1)
a standard conversion sequence (13.3.3.1.1) is a better conversion sequence than a user-defined conversion sequence or an ellipsis conversion sequence, and
a user-defined conversion sequence (13.3.3.1.2) is a better conversion sequence than an ellipsis conversion sequence (13.3.3.1.3).
历史
我是从 Modern C++ Design 的第 2.7 节开始学习这项技术的。我不确定这是不是它的发明地。但这不是一个糟糕的猜测。这本书已经15年了,还是很好读。