Implement is_destructible with Detected Idiom
Here is my implementation of is_destructible_v
:
template<class T>
struct is_unknown_bound_array : std::false_type
{};
template<class T>
struct is_unknown_bound_array<T> : std::true_type
{};
template<typename T, typename U = std::remove_all_extents_t<T>>
using has_dtor = decltype(std::declval<U&>().~U());
template<typename T>
constexpr bool is_destructible_v
= (std::experimental::is_detected_v<has_dtor, T> or std::is_reference_v<T>)
and not is_unknown_bound_array<T>::value
and not std::is_function_v<T>;
template<typename T>
struct is_destructible : std::bool_constant<is_destructible_v<T>>
{};
clang compiled happily and passed all libstdcxx's testsuite, while gcc failed to compile:
prog.cc:177:47: error: 'std::declval<int&>()' is not of type 'int&'
177 | using has_dtor = decltype(std::declval<U&>().~U());
| ~~~~~~~~~~~~~~~~~~~~^
prog.cc: In substitution of 'template<class T, class U> using has_dtor = decltype (declval<U&>().~ U()) [with T = int&&; U = int&&]':
So, gcc cannot do SFINAE on using has_dtor = decltype(std::declval<U&>().~U());
.
Question:
- Which compiler object to standard here?
- What's the most elegant solution/workaround here? The ways I can think of is a little ugly
c++ language-lawyer c++17 template-meta-programming typetraits
add a comment |
Here is my implementation of is_destructible_v
:
template<class T>
struct is_unknown_bound_array : std::false_type
{};
template<class T>
struct is_unknown_bound_array<T> : std::true_type
{};
template<typename T, typename U = std::remove_all_extents_t<T>>
using has_dtor = decltype(std::declval<U&>().~U());
template<typename T>
constexpr bool is_destructible_v
= (std::experimental::is_detected_v<has_dtor, T> or std::is_reference_v<T>)
and not is_unknown_bound_array<T>::value
and not std::is_function_v<T>;
template<typename T>
struct is_destructible : std::bool_constant<is_destructible_v<T>>
{};
clang compiled happily and passed all libstdcxx's testsuite, while gcc failed to compile:
prog.cc:177:47: error: 'std::declval<int&>()' is not of type 'int&'
177 | using has_dtor = decltype(std::declval<U&>().~U());
| ~~~~~~~~~~~~~~~~~~~~^
prog.cc: In substitution of 'template<class T, class U> using has_dtor = decltype (declval<U&>().~ U()) [with T = int&&; U = int&&]':
So, gcc cannot do SFINAE on using has_dtor = decltype(std::declval<U&>().~U());
.
Question:
- Which compiler object to standard here?
- What's the most elegant solution/workaround here? The ways I can think of is a little ugly
c++ language-lawyer c++17 template-meta-programming typetraits
It seems that GCC tries to make sure that the the type of expressiona
ina.~B()
is the same asB
without instantiating the function template, wandbox.org/permlink/4rhdNq4w7MMSIkcR
– Piotr Skotnicki
Nov 24 '18 at 11:05
msvc also can compile(though it doesn't supportand
,or
,not
) godbolt.org/z/b9-Ii8
– 陳 力
Nov 25 '18 at 10:58
icc can compile: godbolt.org/z/ktZB3w
– 陳 力
Nov 25 '18 at 10:59
add a comment |
Here is my implementation of is_destructible_v
:
template<class T>
struct is_unknown_bound_array : std::false_type
{};
template<class T>
struct is_unknown_bound_array<T> : std::true_type
{};
template<typename T, typename U = std::remove_all_extents_t<T>>
using has_dtor = decltype(std::declval<U&>().~U());
template<typename T>
constexpr bool is_destructible_v
= (std::experimental::is_detected_v<has_dtor, T> or std::is_reference_v<T>)
and not is_unknown_bound_array<T>::value
and not std::is_function_v<T>;
template<typename T>
struct is_destructible : std::bool_constant<is_destructible_v<T>>
{};
clang compiled happily and passed all libstdcxx's testsuite, while gcc failed to compile:
prog.cc:177:47: error: 'std::declval<int&>()' is not of type 'int&'
177 | using has_dtor = decltype(std::declval<U&>().~U());
| ~~~~~~~~~~~~~~~~~~~~^
prog.cc: In substitution of 'template<class T, class U> using has_dtor = decltype (declval<U&>().~ U()) [with T = int&&; U = int&&]':
So, gcc cannot do SFINAE on using has_dtor = decltype(std::declval<U&>().~U());
.
Question:
- Which compiler object to standard here?
- What's the most elegant solution/workaround here? The ways I can think of is a little ugly
c++ language-lawyer c++17 template-meta-programming typetraits
Here is my implementation of is_destructible_v
:
template<class T>
struct is_unknown_bound_array : std::false_type
{};
template<class T>
struct is_unknown_bound_array<T> : std::true_type
{};
template<typename T, typename U = std::remove_all_extents_t<T>>
using has_dtor = decltype(std::declval<U&>().~U());
template<typename T>
constexpr bool is_destructible_v
= (std::experimental::is_detected_v<has_dtor, T> or std::is_reference_v<T>)
and not is_unknown_bound_array<T>::value
and not std::is_function_v<T>;
template<typename T>
struct is_destructible : std::bool_constant<is_destructible_v<T>>
{};
clang compiled happily and passed all libstdcxx's testsuite, while gcc failed to compile:
prog.cc:177:47: error: 'std::declval<int&>()' is not of type 'int&'
177 | using has_dtor = decltype(std::declval<U&>().~U());
| ~~~~~~~~~~~~~~~~~~~~^
prog.cc: In substitution of 'template<class T, class U> using has_dtor = decltype (declval<U&>().~ U()) [with T = int&&; U = int&&]':
So, gcc cannot do SFINAE on using has_dtor = decltype(std::declval<U&>().~U());
.
Question:
- Which compiler object to standard here?
- What's the most elegant solution/workaround here? The ways I can think of is a little ugly
c++ language-lawyer c++17 template-meta-programming typetraits
c++ language-lawyer c++17 template-meta-programming typetraits
edited Nov 28 '18 at 10:34
陳 力
asked Nov 24 '18 at 9:28
陳 力陳 力
1,6001723
1,6001723
It seems that GCC tries to make sure that the the type of expressiona
ina.~B()
is the same asB
without instantiating the function template, wandbox.org/permlink/4rhdNq4w7MMSIkcR
– Piotr Skotnicki
Nov 24 '18 at 11:05
msvc also can compile(though it doesn't supportand
,or
,not
) godbolt.org/z/b9-Ii8
– 陳 力
Nov 25 '18 at 10:58
icc can compile: godbolt.org/z/ktZB3w
– 陳 力
Nov 25 '18 at 10:59
add a comment |
It seems that GCC tries to make sure that the the type of expressiona
ina.~B()
is the same asB
without instantiating the function template, wandbox.org/permlink/4rhdNq4w7MMSIkcR
– Piotr Skotnicki
Nov 24 '18 at 11:05
msvc also can compile(though it doesn't supportand
,or
,not
) godbolt.org/z/b9-Ii8
– 陳 力
Nov 25 '18 at 10:58
icc can compile: godbolt.org/z/ktZB3w
– 陳 力
Nov 25 '18 at 10:59
It seems that GCC tries to make sure that the the type of expression
a
in a.~B()
is the same as B
without instantiating the function template, wandbox.org/permlink/4rhdNq4w7MMSIkcR– Piotr Skotnicki
Nov 24 '18 at 11:05
It seems that GCC tries to make sure that the the type of expression
a
in a.~B()
is the same as B
without instantiating the function template, wandbox.org/permlink/4rhdNq4w7MMSIkcR– Piotr Skotnicki
Nov 24 '18 at 11:05
msvc also can compile(though it doesn't support
and
, or
, not
) godbolt.org/z/b9-Ii8– 陳 力
Nov 25 '18 at 10:58
msvc also can compile(though it doesn't support
and
, or
, not
) godbolt.org/z/b9-Ii8– 陳 力
Nov 25 '18 at 10:58
icc can compile: godbolt.org/z/ktZB3w
– 陳 力
Nov 25 '18 at 10:59
icc can compile: godbolt.org/z/ktZB3w
– 陳 力
Nov 25 '18 at 10:59
add a comment |
1 Answer
1
active
oldest
votes
GCC seems to be broken when handling ~T()
where T
is a reference of scalar type.
It accepts the following code, which is clearly buggy per [expr.pseudo]/2:
template<typename T> using tester = decltype(int{}.~T(), char{});
tester<int&> ch;
int main() {}
I would use if constexpr
to implement:
template<class T>
constexpr bool my_is_destructible() {
if constexpr (std::is_reference_v<T>) {
return true;
} else if constexpr (std::is_same_v<std::remove_cv_t<T>, void>
|| std::is_function_v<T>
|| is_unknown_bound_array<T>::value ) {
return false;
} else if constexpr (std::is_object_v<T>) {
return std::experimental::is_detected_v<has_dtor, T>;
} else {
return false;
}
}
It works with GCC too.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53456848%2fimplement-is-destructible-with-detected-idiom%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
GCC seems to be broken when handling ~T()
where T
is a reference of scalar type.
It accepts the following code, which is clearly buggy per [expr.pseudo]/2:
template<typename T> using tester = decltype(int{}.~T(), char{});
tester<int&> ch;
int main() {}
I would use if constexpr
to implement:
template<class T>
constexpr bool my_is_destructible() {
if constexpr (std::is_reference_v<T>) {
return true;
} else if constexpr (std::is_same_v<std::remove_cv_t<T>, void>
|| std::is_function_v<T>
|| is_unknown_bound_array<T>::value ) {
return false;
} else if constexpr (std::is_object_v<T>) {
return std::experimental::is_detected_v<has_dtor, T>;
} else {
return false;
}
}
It works with GCC too.
add a comment |
GCC seems to be broken when handling ~T()
where T
is a reference of scalar type.
It accepts the following code, which is clearly buggy per [expr.pseudo]/2:
template<typename T> using tester = decltype(int{}.~T(), char{});
tester<int&> ch;
int main() {}
I would use if constexpr
to implement:
template<class T>
constexpr bool my_is_destructible() {
if constexpr (std::is_reference_v<T>) {
return true;
} else if constexpr (std::is_same_v<std::remove_cv_t<T>, void>
|| std::is_function_v<T>
|| is_unknown_bound_array<T>::value ) {
return false;
} else if constexpr (std::is_object_v<T>) {
return std::experimental::is_detected_v<has_dtor, T>;
} else {
return false;
}
}
It works with GCC too.
add a comment |
GCC seems to be broken when handling ~T()
where T
is a reference of scalar type.
It accepts the following code, which is clearly buggy per [expr.pseudo]/2:
template<typename T> using tester = decltype(int{}.~T(), char{});
tester<int&> ch;
int main() {}
I would use if constexpr
to implement:
template<class T>
constexpr bool my_is_destructible() {
if constexpr (std::is_reference_v<T>) {
return true;
} else if constexpr (std::is_same_v<std::remove_cv_t<T>, void>
|| std::is_function_v<T>
|| is_unknown_bound_array<T>::value ) {
return false;
} else if constexpr (std::is_object_v<T>) {
return std::experimental::is_detected_v<has_dtor, T>;
} else {
return false;
}
}
It works with GCC too.
GCC seems to be broken when handling ~T()
where T
is a reference of scalar type.
It accepts the following code, which is clearly buggy per [expr.pseudo]/2:
template<typename T> using tester = decltype(int{}.~T(), char{});
tester<int&> ch;
int main() {}
I would use if constexpr
to implement:
template<class T>
constexpr bool my_is_destructible() {
if constexpr (std::is_reference_v<T>) {
return true;
} else if constexpr (std::is_same_v<std::remove_cv_t<T>, void>
|| std::is_function_v<T>
|| is_unknown_bound_array<T>::value ) {
return false;
} else if constexpr (std::is_object_v<T>) {
return std::experimental::is_detected_v<has_dtor, T>;
} else {
return false;
}
}
It works with GCC too.
edited Nov 24 '18 at 13:35
answered Nov 24 '18 at 12:33
llllllllllllllllllll
13.6k41742
13.6k41742
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53456848%2fimplement-is-destructible-with-detected-idiom%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
It seems that GCC tries to make sure that the the type of expression
a
ina.~B()
is the same asB
without instantiating the function template, wandbox.org/permlink/4rhdNq4w7MMSIkcR– Piotr Skotnicki
Nov 24 '18 at 11:05
msvc also can compile(though it doesn't support
and
,or
,not
) godbolt.org/z/b9-Ii8– 陳 力
Nov 25 '18 at 10:58
icc can compile: godbolt.org/z/ktZB3w
– 陳 力
Nov 25 '18 at 10:59