CPP静态“多态”的几种实现方案
2023-12-15 10:40:09
我们这里说的多态,不单指C++中的多态语法,广义的来讲,就是根据传入参数数量或者参数类型的差异,执行不同的动作。现在我们有这样的业务场景:在C++中,根据参数数量改变行为的场景下,有以下几种常见的解决方案:
1. 函数重载
这是最直接的方法,你可以为每个参数数量定义一个不同的函数。但是,这种方法在参数数量较多时会变得很繁琐。
template<typename Ty>
void doSt( Ty v)
{
std::cout << "[" << __FUNCTION__ << ":" << __LINE__ << "] " << v << std::endl;
}
/// 模板特化
template<>
void doSt(int v)
{
std::cout << "[" << __FUNCTION__ << ":" << __LINE__ << "] " << v << std::endl;
}
/// 模板函数重载 : 两个参数,参数一致
template<typename Ty>
void doSt(Ty v1, Ty v2)
{
std::cout << "[" << __FUNCTION__ << ":" << __LINE__ << "] " << v1 << " " << v2 << std::endl;
}
/// 模板函数重载:两个参数,参数不同
template <typename _Ty1,typename _Ty2,
typename std::enable_if<!std::is_same<_Ty1, _Ty2>::value>::type* = nullptr >
void doSt(_Ty1 v1,_Ty2 v2)
{
std::cout << "[" << __FUNCTION__ << ":" << __LINE__ << "] " << v1 << " " << v2 << std::endl;
}
/// ... 多个参数,多种参数类型
/// 我麻了
void foo_()
{
doSt<int>(10);
doSt<int>(2,3);
doSt<int,std::string>(8,"b");
// ...
}
2. 可变参数模板
C++11引入了可变参数模板,它可以接受任意数量的参数。你可以在函数模板中使用可变参数模板,然后在函数体中使用递归或者折叠表达式来处理所有的参数。
// 定义处理函数
template<typename T>
void handle(const T& t)
{
std::cout << "General handle for type: " << typeid(T).name() << ", value: " << t << std::endl;
}
// 为特定类型特化处理函数
template<>
void handle<int>(const int& t)
{
std::cout << "Handle for int: " << t << std::endl;
}
template<>
void handle<std::string>(const std::string& t)
{
std::cout << "Handle for string: " << t << std::endl;
}
// 使用可变参数模板处理任意数量的参数
template<typename T>
void process(const T& t)
{
handle(t);
}
template<typename T, typename... Args>
void process(const T& t, const Args&... args)
{
handle(t);
process(args...); // 递归调用,处理剩余的参数
}
3. std::initializer_list
如果所有的参数都是同一类型,你可以使用 std::initializer_list 来接受任意数量的参数。然后,你可以遍历这个 std::initializer_list 来处理所有的参数。
#include <iostream>
#include <initializer_list>
template <typename _Ty>
void print(std::initializer_list<_Ty> args)
{
for (const auto& arg : args) {
std::cout << arg << " ";
}
std::cout << std::endl;
}
void test_print()
{
print<int>({1, 2, 3, 4, 5}); // 输出:1 2 3 4 5
print<std::string>({"this","is", "a","joke~"});
}
4. 宏
如你所见,你也可以使用宏来实现这种效果。通过定义一系列的宏,你可以根据参数数量来选择使用哪一个宏。然而,这种方法在C++中并不常见,因为它的可读性和可维护性都不如上述的方法。
#include <iostream>
#include <string>
using namespace std;
#define GLUE(x, y) x y
#define RETURN_ARG_COUNT(_1_, _2_, _3_, _4_, _5_, count, ...) count
#define EXPAND_ARGS(args) RETURN_ARG_COUNT args
#define COUNT_ARGS_MAX5(...) EXPAND_ARGS((__VA_ARGS__, 5, 4, 3, 2, 1, 0))
#define OVERLOAD_MACRO2(name, count) name##count
#define OVERLOAD_MACRO1(name, count) OVERLOAD_MACRO2(name, count)
#define OVERLOAD_MACRO(name, count) OVERLOAD_MACRO1(name, count)
#define CALL_OVERLOAD(name, ...) GLUE(OVERLOAD_MACRO(name, COUNT_ARGS_MAX5(__VA_ARGS__)), (__VA_ARGS__))
#define ERROR1(title) printf("Error: %s\n", title)
#define ERROR2(title, message)\
ERROR1(title);\
printf("Message: %s\n", message)
#define ERROR(...) CALL_OVERLOAD(ERROR, __VA_ARGS__)
#define ASSERT1(expr) singleArgumentExpansion(expr)
#define ASSERT2(expr, explain) twoArgumentExpansion(expr, explain)
#define ASSERT(...) CALL_OVERLOAD(ASSERT, __VA_ARGS__)
#define ERROR1(title) printf("Error: %s\n", title)
#define ERROR2(title, message)\
ERROR1(title);\
printf("Message: %s\n", message)
#define ERROR_CHOOSE_HELPER2(count) ERROR##count
#define ERROR_CHOOSE_HELPER1(count) ERROR_CHOOSE_HELPER2(count)
#define ERROR_CHOOSE_HELPER(count) ERROR_CHOOSE_HELPER1(count)
#define ERROR(...) GLUE(ERROR_CHOOSE_HELPER(COUNT_ARGS_MAX5(__VA_ARGS__)),\
(__VA_ARGS__))
#define ASSERT1(expr) singleArgumentExpansion(expr)
#define ASSERT2(expr, explain) twoArgumentExpansion(expr, explain)
#define ASSERT_CHOOSE_HELPER2(count) ASSERT##count
#define ASSERT_CHOOSE_HELPER1(count) ASSERT_CHOOSE_HELPER2(count)
#define ASSERT_CHOOSE_HELPER(count) ASSERT_CHOOSE_HELPER1(count)
#define ASSERT(...) GLUE(ASSERT_CHOOSE_HELPER(COUNT_ARGS_MAX5(__VA_ARGS__)),\
(__VA_ARGS__))
void test_error(const std::string& s,...)
{
//ASSERT("one"); // singleArgumentExpansion(one)
//ASSERT("two", "foopy"); // twoArgumentExpansion(two, "foopy")
ERROR("Only print a title");
ERROR("Error title", "Extended error description");
}
这些方法各有优缺点,你应该根据你的具体需求来选择最合适的方法
文章来源:https://blog.csdn.net/weixin_39568531/article/details/134999318
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!