Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to choose constructor conditionally?

51 views
Skip to first unread message

wij

unread,
Dec 23, 2022, 4:26:24 AM12/23/22
to
template <typename T> struct AA {
T m_val;

void f(const T& arg) {
m_val.~T();
new (&m_val) T(arg); // if T(T&) available
// new (&m_val) T(); // if T() available
}
};

How should AA::f be written depending on T(T&) or T() is available?

Öö Tiib

unread,
Dec 23, 2022, 5:24:56 AM12/23/22
to
To detect such things one can use std::is_copy_constructible and
std::is_default_constructible from <type_traits>.

<https://en.cppreference.com/w/cpp/meta>

wij

unread,
Dec 23, 2022, 8:53:18 AM12/23/22
to
What if the constructor is different, e.g. T(T*, size_t)? Besides, I cannot
see such a type "is_xxx_constructible<T>::value" is helpful.

Paavo Helde

unread,
Dec 23, 2022, 9:11:46 AM12/23/22
to
Maybe you want perfect forwarding?

template <typename T> struct AA {
T m_val;

template<class... ARGTYPES>
void f(ARGTYPES&&... args) {
m_val.~T();
new (&m_val) T(std::forward<ARGTYPES>(args)...);
}
};

int main() {

AA<int> x;
x.f(12);

AA<std::string> y;
y.f(10, 'A');

}

Bo Persson

unread,
Dec 23, 2022, 9:57:19 AM12/23/22
to
On 2022-12-23 at 14:53, wij wrote:
> On Friday, December 23, 2022 at 6:24:56 PM UTC+8, Öö Tiib wrote:
>> On Friday, 23 December 2022 at 11:26:24 UTC+2, wij wrote:
>>> template <typename T> struct AA {
>>> T m_val;
>>>
>>> void f(const T& arg) {
>>> m_val.~T();
>>> new (&m_val) T(arg); // if T(T&) available
>>> // new (&m_val) T(); // if T() available
>>> }
>>> };
>>>
>>> How should AA::f be written depending on T(T&) or T() is available?
>> To detect such things one can use std::is_copy_constructible and
>> std::is_default_constructible from <type_traits>.
>>
>> <https://en.cppreference.com/w/cpp/meta>
>
> What if the constructor is different, e.g. T(T*, size_t)?

Then you have is_constructible_v<T, T*, size_t>

> Besides, I cannot
> see such a type "is_xxx_constructible<T>::value" is helpful.

You can check for the set of parameters you expect to use

if constexpr (is_constructible_v<T, T*, size_t>)
new (&m_val) T(param1, param2);

And perhaps you should use is_nothrow_constructible to not have the
unpleasant surprise of leaving the scope with a destroyed object.

wij

unread,
Dec 23, 2022, 11:46:01 AM12/23/22
to
#include <iostream>
#include <utility>
#include <type_traits>

using namespace std;

struct DD {
DD() { cout << "DD() ";};
// DD(const DD&) { cout << "DD(const DD&) "; };
// DD(int,char) { cout << "DD(int,char) "; };
// DD(size_t,char) { cout << "DD(size_t,char) "; };
~DD() { cout << "~DD() "; };
};

template <typename T> struct AA {
T m_val;

void f() {
m_val.~T();
if constexpr (is_constructible<T, int, char>::value) {
cout << "new1: ";
new (&m_val) T(int(1), char(2));
} else if constexpr (is_constructible<T, size_t, char>::value) {
cout << "new2: ";
new (&m_val) T(size_t(1), char(2));
} else if constexpr (is_copy_constructible<T>::value) {
cout << "new3: ";
new (&m_val) T(m_val);
} else if constexpr (is_constructible<T, const T&>::value) {
cout << "new4: ";
new (&m_val) T(m_val);
} else if constexpr (is_default_constructible<T>::value) {
cout << "new5: ";
new (&m_val) T();
} else {
cout << "Fail\n";
}
};

};

int main()
{
AA<DD> x;
x.f();
cout << "\n";
return 0;
}

-------------------
Thanks, Bo Persson and Paavo Helde. Tested fine.
I did not know the syntax " if constexpr (is_constructible<T,int,char>::value)".

Bonita Montero

unread,
Dec 24, 2022, 2:58:02 AM12/24/22
to
if constexpr( is_copy_constructible_v<T> )
or
if constexpr( is_default_constructible_v<T> )

Mut...@dastardlyhq.com

unread,
Dec 24, 2022, 6:29:29 AM12/24/22
to
I've often wondered why they had to overload constexpr for these sorts of
tests. Why not just have:

if (is_copy_constructible_v(T)) ?

After all, the typeid(T) built-in already works like that.

Paavo Helde

unread,
Dec 24, 2022, 11:58:04 AM12/24/22
to
constexpr is not needed for is_copy_constructible_v(), but for the next
line which would presumable actually attempt to copy-construct the
thing. This next line would trigger a compiler error otherwise.

Bonita Montero

unread,
Dec 24, 2022, 12:10:03 PM12/24/22
to
If constexpr makes it possible that the code inside the if-block
is only syntactically compileable. I.e. if you use a placemnt
new inside the if block the code is actually only compiled if
the constexpr expression is true.

0 new messages