Trait sprawdzający dostępność konstruktorów domyślnych

0

Witam!

Czytam ostatnio artykuł o generycznym singletonie i trafiłem tam na fragment kodu, który niestety nie bardzo rozumiem. Prosiłbym o wytłumaczenie jego dokładnego działania. Tutaj kod:

namespace std
{
 
  template <typename T>
  struct is_default_or_protected_constructible
  {
    struct X : T {};
    static const auto value = std::is_default_constructible<X>::value;
  };
 
}

Chodzi szczególnie o fragment:

struct X : T {} 

Podany kod ma rozstrzygać czy dany typ umożliwia zainicjowanie instancji klasy przez konstruktor domyślny. is_default_constructible<X> mówi nam tylko o konstruktorach znajdujących się w sekcji public klasy. Dlaczego zatem po odziedziczeniu z takiej klasy (w tym wypadku T) nagle możemy dowiedzieć się czegoś dodatkowego o jej konstruktorach, które do tej pory były protected?

1

Bo klasa X ma dostęp do składowych protected T, w tym konstruktorów.

Tak swoją drogą, teraz tego traita zapisałbym tak:

namespace detail
{

template<typename T, bool is_final = std::is_final<T>::value>
struct is_default_or_protected_constructible_helper
{
	struct X : T {};
	static constexpr bool value = std::is_default_constructible<X>::value;
};

template<typename T>
struct is_default_or_protected_constructible_helper<T, true>:
		std::is_default_constructible<T>
{
};

}

template<typename T>
struct is_default_or_protected_constructible:
		std::integral_constant<bool, detail::is_default_or_protected_constructible_helper<T>::value>
{
};

template<typename T>
constexpr bool is_default_or_protected_constructible_v = is_default_or_protected_constructible<T>::value;
0

Czy std::is_default_constructible nie wymaga tego by konstruktory były w sekcji public?
Cytując artykuł:

Trait ten wymaga żeby konstruktory badanej klasy były dostępne publicznie.
Jeżeli tak nie jest to cały kod wydaje się dla mnie przerostem formy nad treścią bo wystarczyłoby po prostu sprawdzić typ T a nie bawić się w takie dziedziczenie.

2

Wymaga, ale to może być konstruktor wygenerowany przez kompilator, niewidzialny w kodzie. Może na przykładzie:

class Foo
{
protected:
	Foo(){}
};

is_default_constructible<Foo>false
IFF nie jesteś w stanie napisać w kodzie

Foo f; // error
work_on_foo(f);

Teraz weźmy się za dziedziczenie:

class Bar : public Foo
{
public:
	Bar(){}
};

Tę klasę możesz bezproblemowo tworzyć:

Bar b; // OK
work_on_foo(b);
work_on_bar(b);

IFF
is_default_constructible<Bar>true

0

Czyli niezależnie od tego gdzie będzie konstruktor domyślny w klasie dziedziczonej (oprócz private), klasa dziedzicząca wywoła go podczas tworzenia instancji. Zgadza się? I tylko do tego sprowadza się rola tej klasy X?

1

Tak jest.

1 użytkowników online, w tym zalogowanych: 0, gości: 1