C++ 可变模版的高级使用,模仿python plot输入参数写法

C++ 可变模版非常方便,可以实现任意数量的参数输入,下面用C++可变模版模仿python matplotlib.pyplot.plot 函数,实现任意数量参数输入,并且识别输入变量的类型

类型定义

用宏定义定义一些结构体,实现marker、linewidth等标记类型和变量

#define MO_KEYWORD_INPUT(name, type)                                                                                                  \
namespace tag{                                                                                                                        \
    struct name {                                                                                                                     \
        typedef type        Type;                                                                                                     \
        typedef const Type& ConstRef;                                                                                                 \
        typedef Type&       Ref;                                                                                                      \
        typedef ConstRef    StorageType;                                                                                              \
        typedef const void* VoidType;                                                                                                 \
        template <typename T>                                                                                                         \
        static PLT_CONSTEXPR bool AllowedType() { return std::is_same<Type, T>::value; }                                              \
        static VoidType GetPtr(ConstRef arg) {                                                                                        \
            return &arg;                                                                                                              \
        }                                                                                                                             \
        template <class T>                                                                                                            \
        static VoidType GetPtr(const T& arg) {                                                                                        \
            (void)arg;                                                                                                                \
            return nullptr;                                                                                                           \
        }                                                                                                                             \
    };                                                                                                                                \
}                                                                                                                                     \
namespace PLT_ARG_NAMESPACE {                                                                                                         \
    static kwargs::TKeyword<tag::name>& name = kwargs::TKeyword<tag::name>::instance;                                                 \
}

上面的PLT_ARG_NAMESPACE命名空间定义了static类型为tag::name的变量name,赋值的是instance变量,注意,instance变量是结构体TKeyword类型,其中instance成员是static类型,这意味着所有的name共享同一个TKeyword类型

namespace kwargs {
    struct TaggedBase {};
    template <class Tag>
    struct TaggedArgument : public TaggedBase {
        typedef Tag TagType;
        explicit TaggedArgument(typename Tag::StorageType val)  //explicit显示赋值,避免隐式赋值
                : arg(&val) {
        }

        typename Tag::VoidType get() const {
            return arg;
        }

    protected:
        typename Tag::VoidType arg;
    };

    template <class Tag>
    struct TKeyword {
        static TKeyword     instance;   //初始化后所有类的instance共享同一个TKeyword类
        TaggedArgument<Tag> operator=(typename Tag::StorageType data) {
            return TaggedArgument<Tag>(data);
        }
    };
    template <class T>
    TKeyword<T> TKeyword<T>::instance;
}

声明

MO_KEYWORD_INPUT 定义了结构体类型marker、label等,并在PLT_ARG_NAMESPACE命名空间定义了类型为TKeyword的marker、label等变量。

MO_KEYWORD_INPUT(marker,std::string)
MO_KEYWORD_INPUT(label, std::string)
MO_KEYWORD_INPUT(color, std::string)
MO_KEYWORD_INPUT(linewidth, int8_t)
MO_KEYWORD_INPUT(alpha, float )
MO_KEYWORD_INPUT(edgecolor, std::string)
MO_KEYWORD_INPUT(markersize, double )
#define DEFAULT_LEGEND      ""
#define DEFAULT_MARKER      "-"
#define DEFAULT_ALPHA       1.0f
#define DEFAULT_COLOR       "none"
#define DEFAULT_EDGECOLOR   "none"
#define DEFAULT_LINEW       2
#define DEFAULT_MARKERSZ    6.0f

可变模版函数的展开

定义函数plotxy,输入x,y坐标,后面的参数包则为曲线的相关设置。

template <class ... Args>
void plotxy(int x,int y,const Args&... args)
{
   auto marker =  GetKeywordInputDefault<tag::marker>(DEFAULT_MARKER,args...);
   std::cout << "maker:"<<marker << endl;
   auto makersize = GetKeywordInputDefault<tag::markersize>(DEFAULT_MARKERSZ,args...);
   cout << "msize:" << makersize << endl;
   auto lw = GetKeywordInputDefault<tag::linewidth>(DEFAULT_LINEW,args...);
   cout << "lw:" << (int)lw << endl;
}

下面的类型Tag是结构体类型,如tag::marker,GetKeywordInputDefault函数第一个参数是默认值DEFAULT_MARKER,第二个参数是参数包,调用GetKeyImpl展开参数包args

template <class Tag, bool Infer = false, class... Args>
typename Tag::ConstRef GetKeywordInputDefault(typename Tag::ConstRef def, const Args&... args) {

    const void* ptr = GetKeyImpl<Tag, Infer>(args...);
    if (ptr)	//如果返回值不是0,表示在参数包args中知道了对应类型的参数
        return *static_cast<const typename Tag::Type*>(ptr);
    //args中没有找到Tag类型的参数,返回默认值
    return def;
}
参数包展开的终止函数
template <class Tag, bool Infer = false>
typename Tag::VoidType GetKeyImpl() {   //如果没有找到与def类型一致的类,返回0
    return 0;
}

template <class Tag, bool Infer = false, class T, class... Args>
//kwargs::TaggedBase是类T的基类,则is_base_of为真,则enable_if<true,T>::type为T::type,即定义GetKeyImpl返回值为Tag::VoidType类型
typename std::enable_if<std::is_base_of<kwargs::TaggedBase, T>::value, typename Tag::VoidType>::type
GetKeyImpl(const T& arg, const Args&... args) {
	//如果Tag与T::TagType类型相同,则返回arg的值,否则继续调用GetKeyImpl展开参数包
    return std::is_same<typename T::TagType, Tag>::value ? const_cast<void*>(arg.get()) : const_cast<void*>(GetKeyImpl<Tag, Infer, Args...>(args...));
}

完整代码

#include <iostream>
#include "type_traits"

using namespace std;

#define PLT_CONSTEXPR constexpr
#ifndef PLT_ARG_NAMESPACE
#define PLT_ARG_NAMESPACE
#endif

#define MO_KEYWORD_INPUT(name, type)                                                                                                  \
namespace tag{                                                                                                                        \
    struct name {                                                                                                                     \
        typedef type        Type;                                                                                                     \
        typedef const Type& ConstRef;                                                                                                 \
        typedef Type&       Ref;                                                                                                      \
        typedef ConstRef    StorageType;                                                                                              \
        typedef const void* VoidType;                                                                                                 \
        template <typename T>                                                                                                         \
        static PLT_CONSTEXPR bool AllowedType() { return std::is_same<Type, T>::value; }                                              \
        static VoidType GetPtr(ConstRef arg) {                                                                                        \
            return &arg;                                                                                                              \
        }                                                                                                                             \
        template <class T>                                                                                                            \
        static VoidType GetPtr(const T& arg) {                                                                                        \
            (void)arg;                                                                                                                \
            return nullptr;                                                                                                           \
        }                                                                                                                             \
    };                                                                                                                                \
}                                                                                                                                     \
namespace PLT_ARG_NAMESPACE {                                                                                                         \
    static kwargs::TKeyword<tag::name>& name = kwargs::TKeyword<tag::name>::instance;                                                 \
}

namespace kwargs {
    struct TaggedBase {};
    template <class Tag>
    struct TaggedArgument : public TaggedBase {
        typedef Tag TagType;
        explicit TaggedArgument(typename Tag::StorageType val)  //explicit显示赋值,避免隐式赋值
                : arg(&val) {
        }

        typename Tag::VoidType get() const {
            return arg;
        }

    protected:
        typename Tag::VoidType arg;
    };

    template <class Tag>
    struct TKeyword {
        static TKeyword     instance;   //初始化后所有类的instance共享同一个TKeyword类
        TaggedArgument<Tag> operator=(typename Tag::StorageType data) {
            return TaggedArgument<Tag>(data);
        }
    };
    template <class T>
    TKeyword<T> TKeyword<T>::instance;
}

MO_KEYWORD_INPUT(marker,std::string)
MO_KEYWORD_INPUT(label, std::string)
MO_KEYWORD_INPUT(color, std::string)
MO_KEYWORD_INPUT(linewidth, int8_t)
MO_KEYWORD_INPUT(alpha, float )
MO_KEYWORD_INPUT(edgecolor, std::string)
MO_KEYWORD_INPUT(markersize, double )
#define DEFAULT_LEGEND      ""
#define DEFAULT_MARKER      "-"
#define DEFAULT_ALPHA       1.0f
#define DEFAULT_COLOR       "none"
#define DEFAULT_EDGECOLOR   "none"
#define DEFAULT_LINEW       2
#define DEFAULT_MARKERSZ    6.0f

template <class Tag, bool Infer = false>
typename Tag::VoidType GetKeyImpl() {   //如果没有找到与def类型一致的类,返回0
    return 0;
}

template <class Tag, bool Infer = false, class T, class... Args>
typename std::enable_if<std::is_base_of<kwargs::TaggedBase, T>::value, typename Tag::VoidType>::type
GetKeyImpl(const T& arg, const Args&... args) {
    return std::is_same<typename T::TagType, Tag>::value ? const_cast<void*>(arg.get()) : const_cast<void*>(GetKeyImpl<Tag, Infer, Args...>(args...));
}

template <class Tag, bool Infer = false, class... Args>
typename Tag::ConstRef GetKeywordInputDefault(typename Tag::ConstRef def, const Args&... args) {

    const void* ptr = GetKeyImpl<Tag, Infer>(args...);
    if (ptr)
        return *static_cast<const typename Tag::Type*>(ptr);
    return def;
}


template <class ... Args>
void plotxy(int x,int y,const Args&... args)
{
   auto marker =  GetKeywordInputDefault<tag::marker>(DEFAULT_MARKER,args...);
   std::cout << "maker:"<<marker << endl;
   auto makersize = GetKeywordInputDefault<tag::markersize>(DEFAULT_MARKERSZ,args...);
   cout << "msize:" << makersize << endl;
   auto lw = GetKeywordInputDefault<tag::linewidth>(DEFAULT_LINEW,args...);
   cout << "lw:" << (int)lw << endl;
}

struct learn{
    static learn l; //static类成员,所有l变量共享同一地址
    static int count;
};

int learn::count = 100; //静态成员需要外部初始化

int main() {
//    learn l1;
//    l1.count = 10;
//    learn l2;
//    cout << "l1.cnt:" << l1.count << "  " << "l2.cnt:" << l2.count << endl;

    plotxy(0,0,marker="--",markersize=10.1);


    return 0;
}

代码来源

参考了用Qtchart写matplotlib相似功能的代码,项目为madplotlib

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值