为什么这种转换方法没有编译?

时间:2018-05-12 05:38:23

标签: c++

为什么以下不编译?

#include <cstring>
#include <typeindex>
#include <type_traits>
#include <iterator>
#include <vector>
#include <iostream>

template<typename T>
using element_type_t = std::remove_reference_t<decltype(*std::begin(std::declval<T&>()))>;

template<typename T>
struct is_json_allowed : std::integral_constant<bool,
    std::is_integral_v<T> || std::is_void_v<T>
    || ( std::is_array_v<T> && is_json_allowed<element_type_t<T>>::value )
    || std::is_same_v<T,std::string> || std::is_floating_point_v<T>
> {};

template<typename T>
inline constexpr bool is_json_allowed_v = is_json_allowed<T>::value;

class Node
{
public:

    Node()
    :
        m_type(typeid(void))
    {

    }

    template<typename T>
    std::enable_if_t<is_json_allowed_v<T>,Node&> operator=(const T& rhs)
    {
        m_type = typeid(T);
        m_data.resize(sizeof(T));
        std::memcpy(&m_data[0],&rhs,sizeof(T));
    }

    template<typename T>
    Node& operator=(const Node& rhs)
    {
        m_type = rhs.m_type;
        m_data = rhs.m_data;
    }

private:
    std::type_index m_type;
    std::vector<int8_t> m_data;
};

int main()
{
    std::cout << is_json_allowed_v<unsigned int> << std::endl;
    Node x = 34u;

    return 0;
}

编译器(Mingw-Builds 7.3.0)抱怨从unsigned int转换为非标量类型Node。我不明白,赋值运算符应该使用34u的值。

它还抱怨begin中的成员__cont请求,这是非类型const unsigned int。我认为这意味着即使element_type_t类型显然不是数组,unsigned int仍在继续。

1 个答案:

答案 0 :(得分:0)

为了不依赖模板推导中的短路,您可以使用SFINAE和这样的帮助结构。

#include <cstring>
#include <typeindex>
#include <type_traits>
#include <iterator>
#include <vector>
#include <iostream>

struct not_json_allowed {};

template<typename T>
using element_type_t = std::remove_reference_t<decltype(*std::begin(std::declval<T&>()))>;

template <typename T, typename U = void>
struct element_type {
    using type = not_json_allowed;
};

template <typename T>
struct element_type<T, std::enable_if_t<std::is_array_v<T>>> {
    using type = element_type_t<T>;
};

template<typename T>
struct is_json_allowed : std::integral_constant<bool,
    std::is_integral_v<T> || std::is_void_v<T>
    || std::is_same_v<T,std::string> || std::is_floating_point_v<T>
> {};

template<typename T>
inline constexpr bool is_json_allowed_v = is_json_allowed<T>::value || is_json_allowed<typename element_type<T>::type>::value;

class Node
{
public:

    Node()
    :
        m_type(typeid(void))
    {

    }

    template<typename T>
    std::enable_if_t<is_json_allowed_v<T>,Node&> operator=(const T& rhs)
    {
        m_type = typeid(T);
        m_data.resize(sizeof(T));
        std::memcpy(&m_data[0],&rhs,sizeof(T));
        return *this;
    }

    template<typename T>
    Node& operator=(const Node& rhs)
    {
        m_type = rhs.m_type;
        m_data = rhs.m_data;
        return *this;
    }

private:
    std::type_index m_type;
    std::vector<int8_t> m_data;
};

int main()
{
    std::cout << is_json_allowed_v<unsigned int> << std::endl;
    Node x;
    x = 34u;

    return 0;
}

我还将main更改为使用了一个assignement,另一个选项是在Node中添加一个等效的模板构造函数。