按类型特征划分的 C++ 模板方法专业化

C++ template method specialization by type traits

提问人:TreeTownGreen 提问时间:9/20/2023 更新时间:9/20/2023 访问量:80

问:

我正在使用 C++ 11,创建一个类模板。我希望根据模板参数的类型特征(即浮点数/整数、有符号/无符号等)优化某些方法。我知道这可以通过对每个特定特征组合的模板专业化来实现,但这太笨拙了。

取而代之的是,我使用虚拟结构包装器的部分模板专用化来工作(因为据我所知,部分专用化仅适用于结构/类)。

这里的工作示例:

#include<type_traits>
#include<iostream>

template<typename T>
struct A
{
    A( T _x ) : x(_x) {}

    template<typename U, bool foobar = std::is_signed<T>::value>
    struct temp{};

    template<typename U>
    struct temp<U,true>
    {
        static constexpr U diff( A const &left, A const &right ) noexcept
        {
            std::cout << "Signed" << std::endl;
            T d = left.x - right.x;
            return d * d;
        }
    };

    template<typename U>
    struct temp<U,false>
    {
        static constexpr U diff( A const &left, A const &right ) noexcept
        {
            std::cout << "Unsigned" << std::endl;
            T d = left.x < right.x ? right.x - left.x : left.x - right.x;
            return d * d;
        }
    };

    protected:

        T x;
};

int main( int argc, char** argv )
{
    // Unsigned
    A<unsigned int> u1( 10 );
    A<unsigned int> u2( 15 );

    // Method call
    std::cout << A<unsigned int>::temp<unsigned long>::diff( u1, u2 ) << std::endl;

    // Signed
    A<float> f1( -1.23f );
    A<float> f2( 12.3f );

    // Method call
    std::cout << A<float>::temp<double>::diff( f1, f2 ) << std::endl;
}

从模板用户的角度来看,取消引用虚拟结构很麻烦,所以如果可能的话,我特别想改进它。

我对C++的了解远非百科全书,所以我想知道是否有更好的解决方案。最好是C++ 11兼容,但我也很想听听现代C++的替代品。

显然我已经用谷歌搜索过这个,但需要我所有的搜索技能才能使上述内容正常工作。

提前致谢。

C++ C++11 模板 优化 类型

评论


答:

1赞 NathanOliver 9/20/2023 #1

你把它弄得太复杂了。您可以向类添加模板重载,并将这些重载限制为特定条件。为此,您将使用

template<typename T>
struct A
{
    A( T _x ) : x(_x) {}

    template<typename U, bool foobar = std::is_signed<T>::value>
    struct temp{};
    
    // only enabled if U or by default T is signed
    template<typename U = T, typename std::enable_if<std::is_signed<U>::value, bool>::type = true>
    static constexpr U diff( A const &left, A const &right ) noexcept
    {
        std::cout << "Signed" << std::endl;
        T d = left.x - right.x;
        return d * d;
    }

    // only enabled if U or by default T is unsigned
    template<typename U = T, typename std::enable_if<!std::is_signed<U>::value, bool>::type = true>
    static constexpr U diff( A const &left, A const &right ) noexcept
    {
        std::cout << "Unsigned" << std::endl;
        T d = left.x < right.x ? right.x - left.x : left.x - right.x;
        return d * d;
    }
    
    protected:
        T x;
};

然后你的司机变成

int main()
{
    // Unsigned
    A<unsigned int> u1( 10 );
    A<unsigned int> u2( 15 );

    // Method call
    std::cout << A<unsigned int>::diff( u1, u2 ) << std::endl;

    // Signed
    A<float> f1( -1.23f );
    A<float> f2( 12.3f );

    // Method call
    std::cout << A<float>::diff( f1, f2 ) << std::endl;
}

如此实时示例所示

评论

0赞 TreeTownGreen 9/20/2023
感谢您如此及时和有用的回复。工作是一种享受。我喜欢 U != T 的语法很直观,例如 A<float>::d iff<double>( f1, f2 )。再次感谢!