Skip to content

[concepts] deferred substitution into requirements of class template members not implemented #44178

Closed
@marehr

Description

@marehr
Bugzilla Link 44833
Version trunk
OS Linux
CC @CaseyCarter,@erichkeane,@friedkeenan,@h-2,@JohelEGP,@AlexeyDmitriev,@PiliLatiesa,@zygoloid,@saarraz,@HighCommander4,@jwakely

Extended Description

Sorry for this verbose and hard to read code, but I wanted to make this configurable.

This code basically has multiple code paths. If REQUIRES_BUG is set, the impl function uses requires to infer if char_is_valid_for is defined or not. If not impl uses SFINAE.

#include <utility>

// #define REQUIRES_BUG     1 - enable the requires bug, 0 - disable it
// #define FUNCTION_DEFINED 1 - define function char_is_valid_for, 0 - do not define char_is_valid_for 

template <int I> struct priority_tag : priority_tag<I - 1> {};
template <> struct priority_tag<0> {};

struct alphabet_base {};

#if FUNCTION_DEFINED
using expect_return_type = bool;
bool char_is_valid_for(char, alphabet_base) { return true; };
#else
using expect_return_type = int;
#endif

namespace seqan3::detail::adl_only {

template <typename...> void char_is_valid_for(...) = delete;

template <typename alph_t>
struct char_is_valid_for_fn
{
    using s_alph_t = alph_t;

#if REQUIRES_BUG
    template <typename t>
    static decltype(auto) impl(priority_tag<1>, t v)
        requires requires { (char_is_valid_for(v, s_alph_t{})); }
    { return (char_is_valid_for(v, s_alph_t{})); }
#else
    template <typename t>
    static auto impl(priority_tag<1>, t v)
        -> std::enable_if_t<true, decltype(char_is_valid_for(v, s_alph_t{}))>
    { return (char_is_valid_for(v, s_alph_t{})); }
#endif

    template <typename t, typename = void>
    static decltype(auto) impl(priority_tag<0>, t v) { return 0; }
};
} // namespace seqan3::detail::adl_only

int main() {
  auto a = seqan3::detail::adl_only::char_is_valid_for_fn<alphabet_base>::impl(priority_tag<1>{}, char{});
  static_assert(std::is_same_v<decltype(a), expect_return_type>);
}

As you can see on https://godbolt.org/z/tyeiJ2 when defining clang++ -std=c++2a -DREQUIRES_BUG=1 -DFUNCTION_DEFINED=0 the requires block should silently see that the requires is not valid (because of a deleted function) and skip to the next definition.

Error Message:

<source>:31:15: error: call to deleted function 'char_is_valid_for'
    { return (char_is_valid_for(v, s_alph_t{})); }
              ^~~~~~~~~~~~~~~~~

<source>:45:75: note: in instantiation of function template specialization 'seqan3::detail::adl_only::char_is_valid_for_fn<alphabet_base>::impl<char>' requested here

  auto a = seqan3::detail::adl_only::char_is_valid_for_fn<alphabet_base>::impl(priority_tag<1>{}, char{});
                                                                          ^

<source>:20:29: note: candidate function [with $0 = <>] has been explicitly deleted
template <typename...> void char_is_valid_for(...) = delete;
                            ^

<source>:45:8: error: variable has incomplete type 'void'
  auto a = seqan3::detail::adl_only::char_is_valid_for_fn<alphabet_base>::impl(priority_tag<1>{}, char{});
       ^

2 errors generated.

Interestingly, if you substitute s_alph_t with alph_t; everything works as expected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugzillaIssues migrated from bugzillac++20clang:frontendLanguage frontend issues, e.g. anything involving "Sema"conceptsC++20 concepts

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions