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

buz*_*sin 1 c++ templates sfinae class-template c++17

考虑以下场景:

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
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

JeJ*_*eJo 5

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

由于您使用的是,我将使用该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;
};
Run Code Online (Sandbox Code Playgroud)

请参阅 godbolt.org 中的现场演示


或者,您显然可以在 中拥有通用实现,Base并且派生类(即启用/禁用std::is_default_constructible_v)可以具有专门化的monomorphic()功能,如下所示:

// 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"; }
};
Run Code Online (Sandbox Code Playgroud)

请参阅 godbolt.org 中的现场演示