为什么在以下代码中使用模板包装器?

时间:2018-08-13 15:05:02

标签: c++

template<typename T>
void write_me(T t)
{}

template<>
void write_me<const std::string&>(const std::string&)
{}

// Q2> what is the purpose of this template?
template <typename T> struct convert_type_to_ref 
{
    typedef T value_type;
};

template <> 
struct convert_type_to_ref <std::string>
{
    typedef std::string const & value_type;
};

template <> 
struct convert_type_to_ref <std::string &>
{
    typedef std::string const & value_type;
};

template <typename T> struct HelloStruct {
    void operator()(const T& t) const {
        write_me<typename convert_type_to_ref<T>::value_type>(t);
    }
};        

template <typename T> struct TValue
{
    typedef T value_type;
};

template <typename T>
void functionAAA(const T& one_arg)
{
    HelloStruct<typename TValue<T>::value_type>()(one_arg);
    // HelloStruct<T>()(one_arg); // Q1> Why not simply use T?
}

我已经看到了一些类似于上面的遗留代码。

问题1>以下两种情况有什么区别?选择案例1的主要好处是什么?

HelloStruct<typename TValue<T>::value_type>()(one_arg); // case 1

VS

HelloStruct<T>()(one_arg); // Why not simply use T?     // case 2

问题2>为什么我们必须在下面引入一种间接方式?

write_me<typename convert_type_to_ref<T>::value_type>(t);

为什么不直接致电如下?

write_me<T>(t);

谢谢

2 个答案:

答案 0 :(得分:1)

对于您的问题1)在这种情况下,两种情况是相同的。但是,在某些情况下,它不能相同。 这个主题称为类型特征,使用第一篇著作可以允许更通用的方式来确定更复杂的数据结构的基本类型。 例如

#include <vector>
#include <list>
#include <type_traits>

    template<class type>
    struct traits
    {
        typedef typename traits<typename type::value_type>::value_type value_type;
    };

    template<>
    struct traits<unsigned char>
    {
        typedef unsigned char value_type;
    };

    template<>
    struct traits<schar>
    {
        typedef schar value_type;
    };

    template<>
    struct traits<unsigned short>
    {
        typedef unsigned short value_type;
    };

    template<>
    struct traits<int>
    {
        typedef int value_type;
    };

    template<>
    struct traits<unsigned>
    {
        typedef unsigned value_type;
    };

    template<>
    struct traits<long>
    {
        typedef long value_type;
    };

    template<>
    struct traits<unsigned long>
    {
        typedef unsigned long value_type;
    };

    template<>
    struct traits<long long>
    {
        typedef long long value_type;
    };

    template<>
    struct traits<float>
    {
        typedef float value_type;
    };

    template<>
    struct traits<double>
    {
        typedef double value_type;
    };

    template<>
    struct traits<long double>
    {
        typedef double value_type;
    };

    int main()
    {

        std::cout<<"CHECK: "<<std::is_same<float, traits<std::vector<std::list<float> > >::value_type>()<<std::endl;
        return 0;
        }

在情况1中,如果复杂结构(例如HelloStruct<typename traits<T>::value_type>()(one_arg);)将创建std::vector<std::list<float> >的实例,而T则调用HelloStruct<float>,而HelloStruct<T>()(one_arg);将创建{{ 1}}。

问题2)间接性只是编译器有关要替换的类型名范围的信息。 例如

HelloStruct<std::vector<std::list<float> > >

希望有帮助。

答案 1 :(得分:1)

  

问题1>以下两种情况有什么区别?选择案例1的主要好处是什么?

HelloStruct<typename TValue<T>::value_type>()(one_arg);HelloStruct<T>()(one_arg);相同。

TValue可以原样使用以避免推论:

template <typename T> void fooA(typename TValue<T>::value_type);
template <typename T> void fooB(T);

然后,fooA(42)无效,需要明确的fooA<int>(42)

fooB(42)fooB<int>(42)均有效。

  

问题2>为什么我们必须在下面引入一种间接方式?

convert_type_to_ref<T>似乎是允许传递参数“效率” (如boost::call_traits)的尝试

如此

write_me<typename convert_type_to_ref<std::string>::value_type>(t);

write_me<const std::string&>(t);

write_me<typename convert_type_to_ref<int>::value_type>(t);

write_me<int>(t);

但在

template <typename T> struct HelloStruct {
    void operator()(const T& t) const {
        write_me<typename convert_type_to_ref<T>::value_type>(t);
    }
};

t已通过const引用传递,因此这种微优化似乎更加多余。