4

我正在一个没有任何标准库的平台上工作,并且我正在尝试实现“类似元组”的类型。

我只需要按类型获取的工具,但static_assert如果类型不存在,我希望编译器发出 a 。不需要断言重复的类型,但这会很好......

这是我尝试过的:

template<class... Args> struct SimpleTuple;

template<> struct SimpleTuple<> {
    SimpleTuple() { }
};

template<class Head, class... Tail>
struct SimpleTuple<Head, Tail...> {
    typedef Head    HeadType;
    typedef SimpleTuple<Tail...> VATailType;

    SimpleTuple(Head head, Tail... tail) : data(head), rest(tail...) { }

    // Does not compile, because explicit specialization in non-namespace
    // scope is not allowed
    template<typename T> T& get() {
        return rest.get<T>();
    }

    template<> Head& get() {
        return data;
    }

    Head data;
    VATailType rest;
};

我知道它为什么会失败,但我不知道如何避免这种限制。

我正在寻找一个尽可能简单的实现。

4

1 回答 1

7

您可以使用 SFINAE 使两个重载中的一个仅参与重载决议,具体取决于类型T是否相同Head

#include <type_traits> // For std::enable_if and std::is_same

template<typename T, 
    typename std::enable_if<!std::is_same<T, Head>::value>::type* = nullptr>
T& get() {
    return rest.get<T>();
}

template<typename T, 
    typename std::enable_if<std::is_same<T, Head>::value>::type* = nullptr>
Head& get() {
    return data;
}

两者std::enable_ifstd::is_same可以轻松实现,以防您无法使用标准库中的那些。例如:

template<typename T, typename U>
struct is_same { static constexpr bool value = false; };

template<typename T>
struct is_same<T, T> { static constexpr bool value = true; };

template<bool C, typename T = void>
struct enable_if { };

template<typename T>
struct enable_if<true, T> { using type = T; };

这是一个活生生的例子

对于静态断言,您可以定义一个简单的 trait 来检查给定类型是否存在于给定的元组类型中(这个 trait 也可以用 来定义,std::conditional实现起来也很简单):

template<typename...> struct SimpleTuple;

template<typename T, typename U>
struct has_type { static constexpr bool value = false; };

template<typename T, typename U, typename... Ts>
struct has_type<T, SimpleTuple<U, Ts...>> 
{ 
    static constexpr bool value = has_type<T, SimpleTuple<Ts...>>::value; 
};

template<typename T, typename... Ts>
struct has_type<T, SimpleTuple<T, Ts...>> 
{ 
    static constexpr bool value = true; 
};

template<typename T>
struct has_type<T, SimpleTuple<>> 
{ 
    static constexpr bool value = false; 
};

然后像这样使用它:

template<typename T, 
    typename enable_if<!is_same<T, Head>::value>::type* = nullptr>
T& get() {
    static_assert(has_type<T, SimpleTuple>::value, "Type not found!");
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^    
    return rest.get<T>();
}

这是一个使用上述内容的实时示例static_assert()

如果您还想测试一个元组是否只包含某个类型一次,您可以使用以下特征,这是对上述has_type特征的简单修改:

template<typename...> struct SimpleTuple;

template<typename T, typename U>
struct has_unique_type { static constexpr bool value = false; };

template<typename T, typename U, typename... Ts>
struct has_unique_type<T, SimpleTuple<U, Ts...>> 
{ 
    static constexpr bool value = has_unique_type<T, SimpleTuple<Ts...>>::value; 
};

template<typename T, typename... Ts>
struct has_unique_type<T, SimpleTuple<T, Ts...>> 
{ 
    static constexpr bool value = 
        !has_unique_type<T, SimpleTuple<Ts...>>::value; 
};

template<typename T>
struct has_unique_type<T, SimpleTuple<>> 
{ 
    static constexpr bool value = false; 
};

并像这样使用它:

template<typename T, 
    typename enable_if<!is_same<T, Head>::value>::type* = nullptr>
T& get() {
    static_assert(has_unique_type<T, SimpleTuple>::value, 
        "Type not found or not unique!");

    return rest.get<T>();
}

这是一个活生生的例子

于 2013-07-03T17:21:09.627 回答