C++ if constexpr

考虑最古老的TagDispatch技术,此技术广泛用于STL标准库

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

struct StringTag {};
struct NumericTag {};

struct Int64 {
    int64_t data_;
    using tag = NumericTag;
};

struct Int32 {
    int data_;
    using tag = NumericTag;
};

struct String {
    std::string data_;
    using tag = StringTag;
};

template<class T>
auto length(T a, NumericTag) 
{ 
    std::stringstream ss;
    ss << a.data_;
    std::cout << ss.str().length() << std::endl;
}

template<class T>
auto length(T a, StringTag){
    std::cout << a.data_.length() << std::endl;
}

template<class T>
auto length(T a) {
    typedef typename T::tag TagType;
    return length(a, TagType{});
}

int main() {

    Int64 kk;
    kk.data_ = 12345;
    length(kk);

    String ss;
    ss.data_ = "12345";
    length(ss);

    return 0;
}

现在用C++17重写,可以把三个分离的length函数,合并成一个。代码如下:

#include <iostream>
#include <string>
#include <sstream>
using namespace std;


struct StringTag {};
struct NumericTag {};

struct Int64 {
    int64_t data_;
    using tag = NumericTag;
};

struct Int32 {
    int data_;
    using tag = NumericTag;
};

struct String {
    std::string data_;
    using tag = StringTag;
};

template<class T>
auto length(T a)
{
    using TagType = typename T::tag;

    if constexpr (is_same<TagType, NumericTag>::value)
    {
        std::stringstream ss;
        ss << a.data_;
        std::cout << ss.str().length() << std::endl;
    }
    else if (is_same<TagType, StringTag>::value) {
        std::cout << a.data_.length() << std::endl;
    }
    else {
        return 0;
    }
}

int main() {

    Int64 kk;
    kk.data_ = 12345;
    length(kk);

    String ss;
    ss.data_ = "12345";
    length(ss);

    return 0;
}

 如果没有机会使用TagDispatch技术,那一定是因为遇到基本数据类型或是自己无法修改源代码的类型。例如:int,就不能获得int::Tag这种信息。

现在我们换到另一种经典的Trait(萃取)技术,也是STL时代就开始的技术。代码如下:

#include <iostream>
#include <string>
using namespace std;

namespace study{

    template <typename T>
    struct is_numeric {
        static const bool value = false;
    };

    template <>
    struct is_numeric<int64_t> {
        static const bool value = true;
    };

    template <>
    struct is_numeric<int> {
        static const bool value = true;
    };
}

namespace study {

    template <typename T>
    struct is_string {
        static const bool value = false;
    };

    template <>
    struct is_string< std::string > {
        static const bool value = true;
    };

}

namespace study {
    template <class T>
    void length(T a, typename std::enable_if< study::is_numeric<T>::value, size_t>::type* dummy = 0) {
        std::stringstream ss;
        ss << a;
        std::cout << ss.str().length() << std::endl;
    }

    template <class T>
    void length(T a, typename std::enable_if< study::is_string<T>::value, size_t>::type* dummy = 0) {
        std::cout << a.length() << std::endl;
    }
}

int main()
{
    int x = 10;

    using namespace study;

    length(x) ;

    std::string str = "12345";
    length(str);

    return 1;
}

可以使用C++17的技术,丢掉繁琐的enable_if之类稀奇古怪的语法:

namespace study {

    template <class T>
    void length(T a) 
    {
        if constexpr ( is_numeric<T>::value )
        {
            std::stringstream ss;
            ss << a;
            std::cout << ss.str().length() << std::endl;
        }
        else if ( is_string<T>::value ) {
            std::cout << a.length() << std::endl;
        }
    }
}

 考虑模板的递归遍历算法,以一个简单的typelist为例,让编译器计算出类型列表中,体积最大的类型。需要一个结束递归的终结器。

namespace study{

    template<class X, class...Xs>
    struct typelist {
        static constexpr size_t max_size() {
            constexpr size_t rest_max_size = typelist<Xs...>::max_size();
            constexpr size_t this_size = sizeof(X);
            return this_size > rest_max_size ? this_size : rest_max_size;
        }
    };

    //结束递归的终结器
    template<class X>
    struct typelist<X> {
        static constexpr size_t max_size() {
            return sizeof(X);
        }
    };
}

int main()
{
    int n = study::typelist<int,char,double>::max_size();
    return 1;
}

C++17的便利设施,可以把终结器写在一起:

namespace study {

    template<class X, class...Xs>
    struct typelist {

        static constexpr size_t max_size() 
        {
            if constexpr(sizeof...(Xs)>0) {
                constexpr size_t rest_max_size = typelist<Xs...>::max_size();
                constexpr size_t this_size = sizeof(X);
                return this_size > rest_max_size ? this_size : rest_max_size;
            }
            else {
                return sizeof(X);
            }
        }
    };
}

int main()
{
    int n = study::typelist<int,char,double>::max_size();
    return 1;
}

总结:if constexpr语法完善了模板元编程的程序路径选择。

原文链接: https://www.cnblogs.com/thomas76/p/8530760.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    C++ if constexpr

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/397586

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月11日 上午9:16
下一篇 2023年4月11日 上午9:16

相关推荐