выбор соответствующего конструктора копирования на основе параметров шаблона

Я хочу выбрать реализацию функции-члена (конструктор копирования) на основе значения аргумента шаблона. Я полагаю, что есть два подхода: SFINAE и частичная специализация шаблона.

последний, предположительно, выглядит так:

#include <iostream>

template<typename A, bool sw>
struct B
{
    B() {}
    B(const B &b);
};

template<typename A>
B<A, false>::B(const B<A, false> &b)
{
    std::cout << "falsen";
}

template<typename A>
B<A, true>::B(const B<A, true> &b)
{
    std::cout << "truen";
}

int main()
{
}

Он не компилируется: nested name specifier 'B<A, false>::' for declaration does not refer into a class, class template or class template partial specialization.

SFINAE подход тоже терпит неудачу:

#include <type_traits>
#include <iostream>

template<typename A, bool sw>
struct B
{
    B() {}

    template<typename U = typename std::enable_if<sw, B>::type>
    B(const U &b)
    {
        std::cout << "truen";
    }

    template<typename U = typename std::enable_if<!sw, B>::type>
    B(const U &b)
    {
        std::cout << "falsen";
    }
};

int main()
{
    {
        B<int, true> b;
        auto bc = b; // cout << true
    }
    {
        B<int, false> b;
        auto bc = b; // cout << false
    }
}

ошибка компиляции здесь constructor cannot be redeclared и no type named 'type' in 'std::enable_if<false, B<int, false> >'; 'enable_if' cannot be used to disable this declaration.

есть ли способ исправить проблемы или иначе выберите соответствующий конструктор копирования на основе параметров шаблона?

3 ответов


template <typename A, bool sw>
struct B
{
    B() = default;

    B(const B& b) : B(b, std::integral_constant<bool, sw>{}) {}

private:
    B(const B& b, std::true_type)
    {
        std::cout << "true\n";
    }

    B(const B& b, std::false_type)
    {
        std::cout << "false\n";
    }
};

демо


Как сказал @Joachim Pileborg в комментарии, вы не можете специализироваться только на одном члене класса, вы должны специализировать весь класс. Таким образом, ваша частичная специализация будет выглядеть так:

template<typename A, bool sw>
struct B
{
    B() {}
    B(const B &b);
};

//Specialize when sw is false
template<typename A>
struct B<A, false>
{
     //The constructor in the specialized struct print false
     B(const B &b)
     {
        std::cout << "false\n";
     }
};

//Specialize when sw is true
template<typename A>
struct B<A, true>
{
    //The constructor in the specialized struct print true
    B(const B &b)
    {
        std::cout << "true\n";
    }
};

лучшее решение, которое вы можете получить для SFINAE, было дано @Piotr Skotnicki


Я знаю, что это минимальный пример, но что не так с

B(const B& b) {
  if(sw) {
    std::cout << "true\n";
  } else {
    std::cout << "false\n";
  }
}