仅针对具有枚举非类型模板参数的 C++ 模板函数的特化

2023-12-21

这个问题与this one https://stackoverflow.com/questions/2155491/hide-function-template-declare-specializations除了处理类型名模板参数之外,我尝试使用枚举非类型模板参数。

在非类型模板参数的情况下,是否可以有一个仅具有专门化的模板化(类成员函数),而没有通用(工作)定义?

  1. 我能够通过在类主体中声明并仅提供专业化来使一个版本正常工作,但是任何使用未定义模板参数的误用调用在链接之前都不会产生错误。更糟糕的是,丢失的符号神秘地引用了枚举的整数值而不是它的名称,因此它会让其他开发人员感到困惑。

  2. 我能够得到BOOST_STATIC_ASSERT引用问题中的技术仅适用于类型名模板参数。

这段代码演示了这个想法。我不想要CAT-version 调用编译:

#include <iostream>
#include <boost/static_assert.hpp>

// CLASS HEADER FILE:
struct foo_class
{
    enum AllowedTypes { DOG, CAT };

    template <AllowedTypes type>
    void add_one_third( double bar ) const
    {
        BOOST_STATIC_ASSERT_MSG(sizeof(type)==0, "enum type not supported.");
    }
};

// CLASS SOURCE FILE
template<>
void foo_class::add_one_third<foo_class::DOG>( double bar ) const
{
    std::cout << "DOG specialization: " << bar + 1./3. << std::endl;
}


// USER SOURCE FILE
int main()
{
    std::cout << "Template Specialization!\n\n";

    foo_class a;
    a.add_one_third<foo_class::DOG>(3.0); // should succeed
    // Compilation fails with or without the following line:
    a.add_one_third<foo_class::CAT>(3.0); // should fail at compile-time

    return 0;
}

背景:我有一个类成员函数,它采用枚举“ArgType”和名称。

void declareKernelArgument( ArgType type, std::string name );

定义变成了if..else..if..else列出六种左右允许的 ArgType 情况。我还必须有最后一个针对不允许的 ArgType 引发异常的情况。我认为将 ArgType 移至模板参数并为每个允许的 ArgType 提供专门化会更清晰。误用会在编译时被发现。


通过类内部结构的部分特化:

#include <iostream>

class foo_class
{
    public:
    enum AllowedTypes { T_DOUBLE, T_INT };

    private:
    template <AllowedTypes type, typename T>
    struct AddOneThird;

    template <typename T>
    struct AddOneThird<T_DOUBLE, T> {
        static void apply(T bar) {
            std::cout << "T_DOUBLE specialization: " << bar + 1.0/3.0 << std::endl;
        }
    };

    public:
    template <AllowedTypes type>
    void add_one_third( double bar ) const {
        AddOneThird<type, double>::apply(bar);
    }
};

int main() {
    foo_class a;
    a.add_one_third<foo_class::T_DOUBLE>(3.0);
    // error: incomplete type ‘foo_class::AddOneThird<(foo_class::AllowedTypes)1u
    // a.add_one_third<foo_class::T_INT>(3.0); // should fail at compile-time

    return 0;
}

具有(朋友)类的完全专业化:

#include <iostream>

class foo_class
{
    public:
    enum AllowedTypes { T_DOUBLE, T_INT };

    // if needed
    // template<AllowedTypes> friend struct AddOneThird;

    public:
    template <AllowedTypes type> void add_one_third( double bar ) const;
};

template <foo_class::AllowedTypes>
struct AddOneThird;

template <>
struct AddOneThird<foo_class::T_DOUBLE> {
    static void apply(double bar) {
        std::cout << "T_DOUBLE specialization: " << bar + 1.0/3.0 << std::endl;
    }
};

template <foo_class::AllowedTypes type>
void foo_class::add_one_third( double bar) const {
    AddOneThird<type>::apply(bar);
}


int main() {
    foo_class a;
    a.add_one_third<foo_class::T_DOUBLE>(3.0);
    // error: incomplete type ‘AddOneThird<(foo_class::AllowedTypes)1u>’ used
    //        in nested name specifier
    //a.add_one_third<foo_class::T_INT>(3.0); // should fail at compile-time

    return 0;
}

使用 C++11 或 boost::enable_if:

#include <iostream>
#include <type_traits>

class foo_class
{
    public:
    enum AllowedTypes { T_DOUBLE, T_INT };

    template <AllowedTypes type>
    typename std::enable_if<type == T_DOUBLE>::type
    add_one_third( double bar ) const {
        std::cout << "T_DOUBLE specialization: " << bar + 1.0/3.0 << std::endl;
    }
};

int main() {
    foo_class a;
    a.add_one_third<foo_class::T_DOUBLE>(3.0);
    // error: no matching function for call to ‘foo_class::add_one_third(double)’
    //a.add_one_third<foo_class::T_INT>(3.0); // should fail at compile-time
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

仅针对具有枚举非类型模板参数的 C++ 模板函数的特化 的相关文章

随机推荐