Implement is_destructible with Detected Idiom












3















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:




  1. Which compiler object to standard here?

  2. What's the most elegant solution/workaround here? The ways I can think of is a little ugly










share|improve this question

























  • 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











  • icc can compile: godbolt.org/z/ktZB3w

    – 陳 力
    Nov 25 '18 at 10:59
















3















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:




  1. Which compiler object to standard here?

  2. What's the most elegant solution/workaround here? The ways I can think of is a little ugly










share|improve this question

























  • 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











  • icc can compile: godbolt.org/z/ktZB3w

    – 陳 力
    Nov 25 '18 at 10:59














3












3








3








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:




  1. Which compiler object to standard here?

  2. What's the most elegant solution/workaround here? The ways I can think of is a little ugly










share|improve this question
















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:




  1. Which compiler object to standard here?

  2. 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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 28 '18 at 10:34







陳 力

















asked Nov 24 '18 at 9:28









陳 力陳 力

1,7441724




1,7441724













  • 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











  • 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











  • 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

















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












1 Answer
1






active

oldest

votes


















3














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.






share|improve this answer

























    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
    });


    }
    });














    draft saved

    draft discarded


















    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









    3














    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.






    share|improve this answer






























      3














      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.






      share|improve this answer




























        3












        3








        3







        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.






        share|improve this answer















        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.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 24 '18 at 13:35

























        answered Nov 24 '18 at 12:33









        llllllllllllllllllll

        13.7k41742




        13.7k41742
































            draft saved

            draft discarded




















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            Wiesbaden

            Marschland

            Dieringhausen