Oct 17, 2025

[C++] SFINAE only match to signature (shallow match)

Notice the difference between ApplyIndexForConstexpr and ApplyIndexForConstexprElse. SFINAE works if there's a signature match; `ApplyIndexForConstexpr` generates 2 explicit template instance while `ApplyIndexForConstexprElse` generates single explicit template instance.
#include <functional>
#include <iostream>
#include <optional>


template <size_t I, typename F>
constexpr std::optional<int> ApplyIndexForConstexpr(F f) {
    if constexpr(sizeof(F) == 1){
        return I;
    } 
    if constexpr(I - 1 == 0){
        return std::nullopt;
    } else {
        return ApplyIndexForConstexpr<I-1>(f);
    }
}

template <size_t I, typename F>
constexpr std::optional<int> ApplyIndexForConstexprElse(F f) {
    if constexpr(sizeof(F) == 1){
        return I;
    } else if constexpr(I - 1 == 0){
        return std::nullopt;
    } else {
        return ApplyIndexForConstexpr<I-1>(f);
    }
}

int main() {
 auto run = []{};
 ApplyIndexForConstexpr<2>(run);
 ApplyIndexForConstexprElse<2>(run);
}
Generated code:
#include <functional>
#include <iostream>
#include <optional>

template<size_t I, typename F>
inline constexpr std::optional<int> ApplyIndexForConstexpr(F f)
{
  if constexpr(sizeof(F) == 1) {
    return std::optional<int>(I);
  } 
  
  if constexpr((I - 1) == 0) {
    return std::optional<int>(std::nullopt_t(std::nullopt));
  } else /* constexpr */ {
    return ApplyIndexForConstexpr<I - 1>(f);
  } 
  
}

/* First instantiated from: insights.cpp:31 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
inline constexpr std::optional<int> ApplyIndexForConstexpr<2, __lambda_30_13>(__lambda_30_13 f)
{
  if constexpr(true) {
    return std::optional<int>(2UL);
  } 
  
  if constexpr(false) {
  } else /* constexpr */ {
    return ApplyIndexForConstexpr<2UL - 1>(__lambda_30_13(f));
  } 
  
}
#endif


/* First instantiated from: insights.cpp:14 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
inline constexpr std::optional<int> ApplyIndexForConstexpr<1, __lambda_30_13>(__lambda_30_13 f)
{
  if constexpr(true) {
    return std::optional<int>(1UL);
  } 
  
  if constexpr(true) {
    return std::optional<int>(std::nullopt_t(std::nullopt));
  } else /* constexpr */ {
  } 
  
}
#endif


template<size_t I, typename F>
inline constexpr std::optional<int> ApplyIndexForConstexprElse(F f)
{
  if constexpr(sizeof(F) == 1) {
    return std::optional<int>(I);
  } else /* constexpr */ {
    if constexpr((I - 1) == 0) {
      return std::optional<int>(std::nullopt_t(std::nullopt));
    } else /* constexpr */ {
      return ApplyIndexForConstexpr<I - 1>(f);
    } 
    
  } 
  
}

/* First instantiated from: insights.cpp:32 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
inline constexpr std::optional<int> ApplyIndexForConstexprElse<2, __lambda_30_13>(__lambda_30_13 f)
{
  if constexpr(true) {
    return std::optional<int>(2UL);
  } else /* constexpr */ {
  } 
  
}
#endif


int main()
{
    
  class __lambda_30_13
  {
    public: 
    inline /*constexpr */ void operator()() const
    {
    }
    
    using retType_30_13 = auto (*)() -> void;
    inline constexpr operator retType_30_13 () const noexcept
    {
      return __invoke;
    };
    
    private: 
    static inline /*constexpr */ void __invoke()
    {
      __lambda_30_13{}.operator()();
    }
    
    public: 
    // inline /*constexpr */ __lambda_30_13(const __lambda_30_13 &) noexcept = default;
    
  };
  
  __lambda_30_13 run = __lambda_30_13{};
  ApplyIndexForConstexpr<2>(__lambda_30_13(run));
  ApplyIndexForConstexprElse<2>(__lambda_30_13(run));
  return 0;
}

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.