简化用于在C ++中将不同类型分派给不同函数的代码

时间:2016-10-20 10:15:54

标签: c++ templates c++14

我想编写一个函数,它为迭代器类型和其他类型打印不同的值。在做了一些研究之后,我想出了这个:

#include <iostream>
#include <iterator>
#include <experimental/type_traits>

namespace details
{
    template <class T, class = void>
    struct is_iterator : std::false_type
    {
    };

    template <class T>
    struct is_iterator<T, std::experimental::void_t<typename std::iterator_traits<T>::value_type>> : std::true_type
    {
    };

    template <class T>
    constexpr auto is_iterator_v = is_iterator<T>::value;
}

template <class T>
std::enable_if_t<!details::is_iterator_v<T>> print(const T &value)
{
    std::cout << value;
}

template <class T>
std::enable_if_t<details::is_iterator_v<T>> print(const T &value)
{
    std::cout << "(IteratorTo ";
    print(*value);
    std::cout << ')';
}

但我认为我的代码有点太长而且有点复杂。是否可以使我的代码更短更清洁?

2 个答案:

答案 0 :(得分:3)

SFINAE是你的朋友:

template <class T>
constexpr std::true_type is_iterator(typename std::iterator_traits<T>::value_type*, int)
{
    return {};
}

template <class T>
constexpr std::false_type is_iterator(void*, long)
{
    return {};
}

template <class T>
constexpr auto is_iterator_v = is_iterator<T>(nullptr, 0);

此外,使用标记调度的print的替代实现,您可能会或可能不会发现更具可读性:

template <class T>
void print(const T &);

namespace details
{
    template <class T>
    void print(const T &value, std::false_type)
    {
        std::cout << value;
    }

    template <class T>
    void print(const T &value, std::true_type)
    {
        std::cout << "(IteratorTo ";
        print(*value);
        std::cout << ')';
    }
}

template <class T>
void print(const T &value)
{
    details::print(value, details::is_iterator_v<T>);
}

答案 1 :(得分:0)

我觉得你的解决方案简单,简洁,干净。

我只看到一个问题:您标记了您的问题C ++ 14,但您建议使用std::experimental::void_t的代码......嗯......实验性而且永远不可用。

但是(如果我没错),使用旧的decltype逗号技巧,你可以在没有void_t的情况下获得相同的结果。

您可以按如下方式编写std::true_type版本(修改后尝试更正Ildjarn指出的问题(谢谢!)):

template <typename T>
struct is_iterator<T,
   decltype(std::declval<typename std::iterator_traits<T>::value_type>(),
      void())> : std::true_type
 { };

此解决方案也适用于C ++ 11。