文章目录
#include <assert.h>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <memory>
#include <string>
#include <type_traits>
#include <vector>
using namespace std;
// 一定要加constexpr,这样在T为int时,return t.substr(1);才不会报错
template <typename T> auto func(T t) {
if constexpr (std::is_same_v<T, int>)
return t + 1;
else
return t.substr(1);
}
// decltype与std::decay_t需要一起配合使用,否则
// func2(v);中,这里decltype(t[0])类型:int&
template <typename T> auto func2(T t) {
if constexpr (std::is_same_v<std::decay_t<decltype(t[0])>, int>)
return t[0] + 1;
else
return t[0].substr(1);
}
//更加正经的方式:
// 需要加typename条件:直接或者间接使用了模板的参数T
// 不需要加typename:using X = std::decay<int>::type;
// 直接依赖:if constexpr (std::is_same_v<typename T::value_type, int>)
// 间接依赖:if constexpr (std::is_same_v<std::decay_t<decltype(t[0])>, int>)
template <typename T> auto func3(T t) {
using X = std::decay<int>::type;
if constexpr (std::is_same_v<typename T::value_type, int>)
return t[0] + 1;
else
return t[0].substr(1);
}
// 判断函数返回值是否是void,方法1:区别小用if constexpr
template <typename F> auto invoke(F f) {
// 判断函数返回值是否是void
// 等价于if constexpr (std::is_void_v<decltype(f())>)
// 等价于:if constexpr
// (std::is_void_v<std::invoke_result_t<F>>),表示函数参数为空时,函数调用的返回值,没有参数变量f的时候可以使用
// 若F没有构造函数,if constexpr
// (std::is_same_v<decltype(std::declval<F>()()), void>)
//进一步判断函数是否是const修饰的,std::declval<F const&>()()
if constexpr (std::is_same_v<decltype(f()), void>) {
f();
printf("leave....\n");
} else {
auto ret = f();
printf("leave....\n");
return ret;
}
}
// 判断函数返回值是否是void,方法2,区别大
// C++20做法:g++ test16.cc -std=c++20
// template <typename F>
// requires(std::is_void_v<std::invoke_result_t<F>>) auto invoke2(F f) { f(); }
// template <typename F>
// requires(!std::is_void_v<std::invoke_result_t<F>>) auto invoke2(F f) {
// auto ret = f();
// return ret;
// }
// 没有requires,C++SFINAE做法:
// 等价于:EQUIRES(std::is_void_v<decltype(std::declval<F>()())>)
#define REQUIRES(x) std::enable_if_t<(x), int> = 0
template <typename F, REQUIRES(std::is_void_v<std::invoke_result_t<F>>)>
auto invoke3(F f) {
f();
}
// 等价于:EQUIRES(!std::is_void_v<decltype(std::declval<F>()())>),因为形参f在这里是没有的,所以只能由编译器构造一个F(),注意lambda的构造函数是不存在的,这里反而能构造一个lambda对象
template <typename F, REQUIRES(!std::is_void_v<std::invoke_result_t<F>>)>
auto invoke3(F f) {
auto ret = f();
return ret;
}
template <typename F, REQUIRES(std::is_void_v<decltype(std::declval<F &>()())>)>
auto invoke4(F f) {
f();
}
template <typename F,
REQUIRES(!std::is_void_v<decltype(std::declval<F &>()())>)>
auto invoke4(F f) {
auto ret = f();
return ret;
}
///
struct myclass {
void dismantle() {
printf("rm -rf course\n"); }
};
struct myteacher {
void rebel() {
printf("rm -rf gench\n"); }
void rebel(int i) {
printf("rm -rf gench-%d\n", i); }
};
// 判断某个成员函数是否存在.C++20做法:
// g++ test16.cc -std=c++20
template <typename T> void gench(T t) {
if constexpr (requires {
t.dismantle(); }) {
t.dismantle();
} else if constexpr (requires {
t.rebel(); }) {
t.rebel();
} else if constexpr (requires(int i) {
t.rebel(i); }) {
for (int i = 1; i <= 2; ++i) {
t.rebel(i);
}
} else if constexpr (requires {
t.rebel(std::declval<int>()); }) {
t.rebel(0);
} else {
printf("======\n");
}
}
/
// 笨蛋方法枚举,每次增加一个类都要写一个全特化,蛋疼
template <typename T> struct enum_has_dismantle {
static constexpr bool value = false;
};
template <> struct enum_has_dismantle<myclass> {
static constexpr bool value = true;
};
template <> struct enum_has_dismantle<myteacher> {
static constexpr bool value = false;
};
template <typename T> void gench2(T t) {
if constexpr (enum_has_dismantle<T>::value) {
t.dismantle();
} else {
printf("======\n");
}
}
/
// 判断某个成员函数是否存在.C++14做法SIFANE:
template <class T, class = void> struct has_dismantle {
static constexpr bool value = false;
};
// std::void_t<>只是关心<>里面的内容是否正确
template <class T>
struct has_dismantle<T, std::void_t<decltype(std::declval<T>().dismantle())>> {
static constexpr bool value = true;
};
template <class T, class = void> struct has_rebel {
static constexpr bool value = false;
};
template <class T>
struct has_rebel<
T, std::void_t<decltype(std::declval<T>().rebel(std::declval<int>()))>> {
static constexpr bool value = true;
};
template <class T, class = void> struct has_nopara_rebel {
static constexpr bool value = false;
};
template <class T>
struct has_nopara_rebel<T, std::void_t<decltype(std::declval<T>().rebel())>> {
static constexpr bool value = true;
};
template <typename T> void gench3(T t) {
if constexpr (has_dismantle<T>::value) {
t.dismantle();
} else if constexpr (has_rebel<T>::value) {
for (int i = 1; i <= 2; ++i) {
t.rebel(i);
}
} else {
printf("======\n");
}
}
// 不使用C++17的constexpr
template <class T, REQUIRES(has_dismantle<T>::value)> void gench4(T t) {
t.dismantle();
}
template <class T, REQUIRES(!has_dismantle<T>::value && has_rebel<T>::value)>
void gench4(T t) {
for (int i = 1; i <= 4; i++) {
t.rebel(i);
}
}
template <class T, REQUIRES(!has_dismantle<T>::value && !has_rebel<T>::value)>
void gench4(T t) {
printf("no any method supported!\n");
}
int main(int argc, char **argv) {
int i = 0;
string s = "hello";
func(i);
func(s);
vector<int> v = {
1, 2, 3};
v.operator[](1);
func2(v);
func3(v);
std::cout << __cplusplus << std::endl;
invoke([]() -> int {
return 1; });
invoke([]() -> void {
return; });
static_assert(std::is_void_v<void>);
static_assert(std::is_void_v<const void>);
static_assert(std::is_void_v<const volatile void>);
invoke4([&]() mutable -> int {
return 1; });
myclass ms;
myteacher mt;
gench(ms);
gench(mt);
gench3(ms);
gench3(mt);
return 0;
}
参考: