c++ - 如果 std::vector 作为 T::Zero 存在,如何生成代码以使用自定义零值初始化 std::vector?

标签 c++ c++11 structure sfinae typetraits

背景

我有一个容器类,它有一个 std::vector<T>我使用采用 size_t n_items 的构造函数初始化的成员.我想用我自己的 Zero() 函数初始化那个 vector returns 0;默认情况下,但如果是静态成员 T::Zero存在我想返回它。

在我的第一次尝试中,我使用了表达式 SFINAE,但是由于不明确的过载而失败了,因为 Zero 的通用版本和 Zero 都具有相同的签名但没有参数。所以现在,我正在尝试使用 operator() 将代码转换为类.

我想我需要使用 std::enable_if不知何故,但我不确定如何编写代码。

尝试失败

#include <cassert>
#include <iostream>
#include <vector>

template<typename T>
struct Zero
{
        T operator() const { return 0; }
};

template<typename T>
struct Zero
{
        auto operator() const ->
                decltype( T::Zero )
        {
                return T::Zero;
        }
};

struct Foo
{
        char m_c;
        static Foo Zero;

        Foo() : m_c( 'a' ) { }
        Foo( char c ) : m_c( c ) { }
        bool operator==( Foo const& rhs ) const { return m_c==rhs.m_c; }
        friend std::ostream& operator<<( std::ostream& os, Foo const& rhs )
        {
                os << (char)(rhs.m_c);
                return os;
        }
};

Foo Foo::Zero( 'z' );

int
main( int argc, char** argv )
{
        std::vector<unsigned>  v( 5, Zero<unsigned>() );
        std::vector<Foo>       w( 3, Zero<Foo>()      );

        for( auto& x : v )
                std::cout << x << "\n";
        std::cout << "---------------------------------\n";
        for( auto& x : w )
        {
                assert( x==Foo::Zero );
                std::cout << x << "\n";
        }

        std::cout << "ZERO = " << Foo::Zero << "\n";

        return 0;
}

最佳答案

#include <string>
#include <iostream>
#include <vector>
#include <type_traits>

namespace detail
{
    template<class T, class = decltype(T::zero)>
    std::true_type has_zero_impl(int);

    template<class T>
    std::false_type has_zero_impl(short);
}

template<class T>
using has_zero = decltype(detail::has_zero_impl<T>(0));

template<class T, class = has_zero<T>>
struct zero
{
    constexpr static T get() { return T(); }
};

template<class T>
struct zero<T, std::true_type>
{
    constexpr static auto get() -> decltype(T::zero)
    {  return T::zero;  }
};

使用示例:

template<>
struct zero<std::string>
{
    static constexpr const char* get()
    {  return "[Empty]";  }
};

struct foo
{
    int m;
    static constexpr int zero = 42;
};

int main()
{
    std::cout << zero<int>::get() << "\n";
    std::cout << zero<std::string>::get() << "\n";
    std::cout << zero<foo>::get() << "\n";
}

没有 trait 的精简版:

template<class T>
struct zero
{
private:
    template<class X>
    constexpr static decltype(X::zero) zero_impl(int)
    { return X::zero; }

    template<class X>
    constexpr static X zero_impl(short)
    { return X(); }

public:
    constexpr static auto get()
    -> decltype(zero_impl<T>(0))
    {
        return zero_impl<T>(0);
    }
};

template<>
struct zero<std::string>
{
    constexpr static const char* get()
    {  return "[Empty]";  }
};

关于c++ - 如果 std::vector 作为 T::Zero 存在,如何生成代码以使用自定义零值初始化 std::vector?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21353810/

相关文章:

c++ - 为什么正则表达式 "([a-z])((?!\\1)[a-z])"会匹配 C++11 中的字符串 "aa"?

c - 用 C 将条目写入文件的结构数组中

swift - 为什么常量约束来自结构实例而不是类实例的属性?

c++ - STL 或 Boost 能否帮助按值对 map 进行排序?

c++ - 为什么 cmake_link_libraries 包含静态库?

c++ - 我可以在从另一个线程插入/删除时访问 C++11 std::map 条目吗?

c - 使用结构求分数的 GCD(简单 C 程序)

c++ - 如何在 C++ 中使用 std::function 访问 Functor 的成员函数?

c++ - 通过 move 同一语句中使用的变量进行捕获

c++ - std::mt19937 和 std::uniform_real_distribution 每次都返回边界值