如何为专用模板类提供更紧凑的定义?

How do I provide a more compact definition for the specialized template classes?

提问人:buzzysin 提问时间:6/24/2023 最后编辑:JeJobuzzysin 更新时间:6/24/2023 访问量:79

问:

请考虑以下情况:

template <
    typename T,
    bool B = std::is_default_constructible_v<T>>
class toy_example;

template<typename T>
class toy_example<T, true>
{
public:
    toy_example() = default; // e.g. for default constructible types
    toy_example(const T& value);

public:
    void monomorphic(T);

private:
    T m_value;
};

template<typename T>
class toy_example<T, false> 
{
public:
    toy_example() = delete; // e.g. for non-default constructible types
    toy_example(const T& value); // Repeated declaration

public:
    void monomorphic(T); // Repeated declaration

private:
    T m_value;
};

// Implementation
template<typename T>
toy_example<T, true>::toy_example(const T& value) : m_value(value) {}

// (Unnecessary?) Repetition
template<typename T>
toy_example<T, false>::toy_example(const T& value) : m_value(value) {}

template<typename T>
toy_example<T, true>::monomorphic(T) 
{
    std::cout << "Behaviour is the same despite specialisation.\n";
    // (P.S) - This is intended behaviour
}

// (Unnecessary?) Repetition
template<typename T>
toy_example<T, false>::monomorphic(T) 
{
    std::cout << "Behaviour is the same despite specialisation.\n";
    // (P.S) - This is intended behaviour
}

如何通过为我希望以相同方式运行的函数(在本例中为初始化构造函数和函数)提供单个定义来为此类提供更紧凑的定义?monomorphic

我这样做的动机是,在我的代码库中,代码有点冗长,我宁愿不必要地复制它。monomorphic(T)

我知道解决方案可能涉及使用某种基类,但我不确定如何处理这个问题。

C++ 模板 C++17 SFINAE 类模板

评论


答:

5赞 JeJo 6/24/2023 #1

如何通过为我希望以相同方式表现的函数(在本例中为初始化构造函数和单态函数)提供单个定义,为此类提供更紧凑的定义?

由于您使用的是 ,我将使用 if constexpr 功能,通过该功能可以将两个实现保持在同一个函数体中。

此外,默认构造函数(和其他通用代码)可以针对同一类中的每个案例进行 SFINAEd。

类似的东西。

class ExampleClass
{
public:
    template<typename U = T>
    ExampleClass(std::enable_if_t<std::is_default_constructible_v<U>>* = 0)
    {} // enabled only for default constructible types


    template<typename U = T>
    ExampleClass(
        std::enable_if_t<!std::is_default_constructible_v<U>>* = 0
    ) = delete; // For non-default constructible types

    ExampleClass(const T& value)
        : m_value{ value } {}

public:
    void monomorphic()
    {
        if constexpr (std::is_default_constructible_v<T>)
        {
            std::cout << "default_constructible Impli\n";
        }
        else
        {
            std::cout << "Non-default_constructible Impli\n";
        }
    }

private:
    T m_value;
};

观看现场演示 godbolt.org


或者,您显然可以在 和 中拥有通用实现,派生类(即启用/禁用 )可以具有专用化功能,如下所示:Basestd::is_default_constructible_vmonomorphic()

// Common base class
template<typename T> class Base
{
public:
    template<typename U = T>
    Base(std::enable_if_t<std::is_default_constructible_v<U>>* = 0)
    {} // enabled only for default constructible types


    template<typename U = T>
    Base(std::enable_if_t<!std::is_default_constructible_v<U>>* = 0)
        = delete; // for non default constructible types

    Base(const T& value)
        : m_value{ value } {}

private:
    T m_value;
};

template <typename T, typename Enable = void> class Derived;

// specialization for true case
template<typename T>
class Derived<T, 
              std::enable_if_t<std::is_default_constructible_v<T>>> 
              : public Base<T>
{
public:
    Derived() = default;
    using Base<T>::Base;
    void monomorphic(){ std::cout << "default_constructible Impli\n"; }
};

// specialization for false case
template<typename T> 
class Derived<T,
              std::enable_if_t<!std::is_default_constructible_v<T>>>
              : public Base<T>
{
public:
    using Base<T>::Base;
    void monomorphic() { std::cout << "Non-default_constructible Impli\n"; }
};

观看现场演示 godbolt.org

评论

0赞 buzzysin 6/24/2023
感谢您的编辑和回答。下次我会尝试更好地格式化我的问题:<