仅对定义了函数的类型执行函数模板内的函数
Execute function inside function template only for those types that have the function defined
我有一个函数模板,它在输入时采用许多不同的类型。在这些类型中,只有一种具有 getInt()
函数。因此,我希望代码 运行 仅针对该类型的函数。请提出解决方案。谢谢
#include <type_traits>
#include <typeinfo>
class X {
public:
int getInt(){
return 9;
}
};
class Y{
};
template<typename T>
void f(T& v){
// error: 'class Y' has no member named 'getInt'
// also tried std::is_same<T, X>::value
if(typeid(T).name() == typeid(X).name()){
int i = v.getInt();// I want this to be called for X only
}
}
int main(){
Y y;
f(y);
}
如果您希望能够为具有函数成员 getInt
的所有类型调用函数 f
,而不仅仅是 X
,您可以为函数 [=] 声明 2 个重载13=]:
对于具有getInt
成员函数的类型,包括classX
对于所有其他类型,包括 class Y
.
C++11/C++17解决方案
考虑到这一点,您可以这样做:
#include <iostream>
#include <type_traits>
template <typename, typename = void>
struct has_getInt : std::false_type {};
template <typename T>
struct has_getInt<T, std::void_t<decltype(((T*)nullptr)->getInt())>> : std::is_convertible<decltype(((T*)nullptr)->getInt()), int>
{};
class X {
public:
int getInt(){
return 9;
}
};
class Y {};
template <typename T,
typename std::enable_if<!has_getInt<T>::value, T>::type* = nullptr>
void f(T& v) {
// only for Y
std::cout << "Y" << std::endl;
}
template <typename T,
typename std::enable_if<has_getInt<T>::value, T>::type* = nullptr>
void f(T& v){
// only for X
int i = v.getInt();
std::cout << "X" << std::endl;
}
int main() {
X x;
f(x);
Y y;
f(y);
}
看看live.
请注意,std::void_t
是在 C++17 中引入的,但是如果你仅限于 C++11,那么你自己实现 void_t
真的很容易:
template <typename...>
using void_t = void;
这里是 C++11 版本 live。
我们在 C++20 中有什么?
C++20 带来了很多好东西,其中之一就是 concepts。以上对 C++11/C++14/C++17 有效的内容在 C++20 中可以显着减少:
#include <iostream>
#include <concepts>
template<typename T>
concept HasGetInt = requires (T& v) { { v.getInt() } -> std::convertible_to<int>; };
class X {
public:
int getInt(){
return 9;
}
};
class Y {};
template <typename T>
void f(T& v) {
// only for Y
std::cout << "Y" << std::endl;
}
template <HasGetInt T>
void f(T& v){
// only for X
int i = v.getInt();
std::cout << "X" << std::endl;
}
int main() {
X x;
f(x);
Y y;
f(y);
}
看看live.
您可以使用 C++17 中的 if constexpr
:
template<typename T>
void f(T& v){
if constexpr(std::is_same_v<T, X>) { // Or better create trait has_getInt
int i = v.getInt();// I want this to be called for X only
}
// ...
}
之前,您将不得不使用重载和 SFINAE 或标签调度。
保持简单和超载。至少从 C++98 开始工作...
template<typename T>
void f(T& v)
{
// do whatever
}
void f(X& v)
{
int result = v.getInt();
}
如果只有一种类型具有 getInt
功能,这就足够了。多了就没那么简单了。有多种方法,这里是一种:
struct PriorityA { };
struct PriorityB : PriorityA { };
template<typename T>
void f_impl(T& t, PriorityA)
{
// generic version
}
// use expression SFINAE (-> decltype part)
// to enable/disable this overload
template<typename T>
auto f_impl(T& t, PriorityB) -> decltype(t.getInt(), void())
{
t.getInt();
}
template<typename T>
void f(T& t)
{
f_impl(t, PriorityB{ } ); // this will select PriorityB overload if it exists in overload set
// otherwise PriorityB gets sliced to PriorityA and calls generic version
}
我有一个函数模板,它在输入时采用许多不同的类型。在这些类型中,只有一种具有 getInt()
函数。因此,我希望代码 运行 仅针对该类型的函数。请提出解决方案。谢谢
#include <type_traits>
#include <typeinfo>
class X {
public:
int getInt(){
return 9;
}
};
class Y{
};
template<typename T>
void f(T& v){
// error: 'class Y' has no member named 'getInt'
// also tried std::is_same<T, X>::value
if(typeid(T).name() == typeid(X).name()){
int i = v.getInt();// I want this to be called for X only
}
}
int main(){
Y y;
f(y);
}
如果您希望能够为具有函数成员 getInt
的所有类型调用函数 f
,而不仅仅是 X
,您可以为函数 [=] 声明 2 个重载13=]:
对于具有
getInt
成员函数的类型,包括classX
对于所有其他类型,包括 class
Y
.
C++11/C++17解决方案
考虑到这一点,您可以这样做:
#include <iostream>
#include <type_traits>
template <typename, typename = void>
struct has_getInt : std::false_type {};
template <typename T>
struct has_getInt<T, std::void_t<decltype(((T*)nullptr)->getInt())>> : std::is_convertible<decltype(((T*)nullptr)->getInt()), int>
{};
class X {
public:
int getInt(){
return 9;
}
};
class Y {};
template <typename T,
typename std::enable_if<!has_getInt<T>::value, T>::type* = nullptr>
void f(T& v) {
// only for Y
std::cout << "Y" << std::endl;
}
template <typename T,
typename std::enable_if<has_getInt<T>::value, T>::type* = nullptr>
void f(T& v){
// only for X
int i = v.getInt();
std::cout << "X" << std::endl;
}
int main() {
X x;
f(x);
Y y;
f(y);
}
看看live.
请注意,std::void_t
是在 C++17 中引入的,但是如果你仅限于 C++11,那么你自己实现 void_t
真的很容易:
template <typename...>
using void_t = void;
这里是 C++11 版本 live。
我们在 C++20 中有什么?
C++20 带来了很多好东西,其中之一就是 concepts。以上对 C++11/C++14/C++17 有效的内容在 C++20 中可以显着减少:
#include <iostream>
#include <concepts>
template<typename T>
concept HasGetInt = requires (T& v) { { v.getInt() } -> std::convertible_to<int>; };
class X {
public:
int getInt(){
return 9;
}
};
class Y {};
template <typename T>
void f(T& v) {
// only for Y
std::cout << "Y" << std::endl;
}
template <HasGetInt T>
void f(T& v){
// only for X
int i = v.getInt();
std::cout << "X" << std::endl;
}
int main() {
X x;
f(x);
Y y;
f(y);
}
看看live.
您可以使用 C++17 中的 if constexpr
:
template<typename T>
void f(T& v){
if constexpr(std::is_same_v<T, X>) { // Or better create trait has_getInt
int i = v.getInt();// I want this to be called for X only
}
// ...
}
之前,您将不得不使用重载和 SFINAE 或标签调度。
保持简单和超载。至少从 C++98 开始工作...
template<typename T>
void f(T& v)
{
// do whatever
}
void f(X& v)
{
int result = v.getInt();
}
如果只有一种类型具有 getInt
功能,这就足够了。多了就没那么简单了。有多种方法,这里是一种:
struct PriorityA { };
struct PriorityB : PriorityA { };
template<typename T>
void f_impl(T& t, PriorityA)
{
// generic version
}
// use expression SFINAE (-> decltype part)
// to enable/disable this overload
template<typename T>
auto f_impl(T& t, PriorityB) -> decltype(t.getInt(), void())
{
t.getInt();
}
template<typename T>
void f(T& t)
{
f_impl(t, PriorityB{ } ); // this will select PriorityB overload if it exists in overload set
// otherwise PriorityB gets sliced to PriorityA and calls generic version
}