PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep

Quick Overview

This question evaluates proficiency in C++ template metaprogramming, type traits, SFINAE and Concepts for compile-time callable signature verification, including handling of noexcept, cv/ref qualifiers and implicit conversions.

  • Medium
  • OpenAI
  • Coding & Algorithms
  • Software Engineer

Implement compile-time function type verification

Company: OpenAI

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: Medium

Interview Round: Technical Screen

Implement a C++20 compile-time utility to verify whether a callable matches a target function type. Requirements: create a primary template is_callable_with_signature<Fn, R(Args...)> that yields true if Fn is invocable with Args... and the return type is convertible to R; provide two implementations— ( 1) SFINAE/traits-based and ( 2) concepts/requires-based; support free functions, lambdas, functors with overloaded operator(), member function pointers, and std::function; include minimal tests with static_assert and examples that should fail to compile if the signature does not match; discuss handling noexcept, cv/ref qualifiers, and implicit conversions.

Quick Answer: This question evaluates proficiency in C++ template metaprogramming, type traits, SFINAE and Concepts for compile-time callable signature verification, including handling of noexcept, cv/ref qualifiers and implicit conversions.

Part 1: Traits-Style Callable Signature Match

You are given the list of callable signatures exposed by a callable object. Think of this as a simplified runtime version of C++ traits such as is_invocable_r. Each string in 'signatures' represents one overload of the callable. The origin of the overload does not matter: a free function, lambda, functor, member-function pointer, or std::function can all be represented the same way. A target signature has the form '(A1,A2,...)->R'. A candidate overload matches the target if: 1. It has the same number of parameters. 2. Every target argument type can be implicitly converted to the candidate parameter type. 3. The candidate return type can be implicitly converted to the target return type. Supported types are: 'bool', 'int', 'long', 'double', 'string', and 'void'. Allowed implicit conversions are: - exact type to itself - bool -> int, long, double - int -> long, double - long -> double - void is only convertible to void - no other conversions are allowed Return True if at least one candidate overload matches the target signature; otherwise return False.

Constraints

  • 0 <= len(signatures) <= 10000
  • Each signature string has length between 4 and 100
  • All signatures are well-formed
  • Types only come from: bool, int, long, double, string, void
  • Only the listed implicit conversions are allowed

Examples

Input: (['(int)->long'], '(int)->double')

Expected Output: True

Explanation: The argument type matches exactly, and the candidate return type long can be widened to double.

Input: (['(double)->int', '(string)->int'], '(int)->long')

Expected Output: True

Explanation: The first overload matches because int can convert to double and int can convert to long on return.

Input: (['()->void'], '()->void')

Expected Output: True

Explanation: Edge case: zero-argument callable with void return matches exactly.

Input: (['(long)->int'], '(double)->int')

Expected Output: False

Explanation: double cannot implicitly convert to long under the allowed rules, so the call is not valid.

Input: ([], '(int)->int')

Expected Output: False

Explanation: Edge case: with no candidate overloads, nothing can match.

Solution

def solution(signatures, target_signature):
    rank = {'bool': 0, 'int': 1, 'long': 2, 'double': 3}

    def convertible(src, dst):
        if src == dst:
            return True
        if src == 'void' or dst == 'void':
            return False
        if src in rank and dst in rank:
            return rank[src] <= rank[dst]
        return False

    def parse(sig):
        sig = ''.join(sig.split())
        left, ret = sig.split('->')
        args_text = left[1:-1]
        args = [] if args_text == '' else args_text.split(',')
        return args, ret

    target_args, target_ret = parse(target_signature)

    for sig in signatures:
        params, ret = parse(sig)
        if len(params) != len(target_args):
            continue
        args_ok = all(convertible(arg, param) for arg, param in zip(target_args, params))
        ret_ok = convertible(ret, target_ret)
        if args_ok and ret_ok:
            return True

    return False

Time complexity: O(N * L), where N is the number of candidate signatures and L is the average signature length. Space complexity: O(L) excluding the input storage.

Hints

  1. Parse each signature into an argument list and a return type. Overloads are just multiple candidate strings.
  2. Model implicit conversion as a directed rule set or numeric rank order, then test every parameter position plus the return type.

Part 2: Concepts-Style Callable Signature Match with Qualifiers

Now extend the matcher to simulate a stricter concepts/requires-style check. Each candidate overload and the target signature begin with a bracketed qualifier list, followed by the function type. The format is: '[q1,q2,...](A1,A2,...)->R' Examples: - '[](int)->double' - '[const,&,noexcept](int)->long' - '[noexcept]()->void' Supported qualifiers are: - 'const' - '&' - '&&' - 'noexcept' A candidate overload matches the target if all of the following hold: 1. It has the same number of parameters. 2. Every target argument type can be implicitly converted to the candidate parameter type. 3. The candidate return type can be implicitly converted to the target return type. 4. If the target requires 'const', the candidate must include 'const'. 5. If the target requires 'noexcept', the candidate must include 'noexcept'. 6. If the target requires '&', the candidate must include '&'. 7. If the target requires '&&', the candidate must include '&&'. 8. If the target omits a qualifier, the candidate may have it or not. Use the same type system and implicit conversion rules as in Part 1. Return True if at least one overload matches; otherwise return False.

Constraints

  • 0 <= len(signatures) <= 10000
  • Each signature string has length between 6 and 120
  • All signatures are well-formed
  • Types only come from: bool, int, long, double, string, void
  • Qualifiers only come from: const, &, &&, noexcept
  • A signature contains at most one of '&' and '&&'
  • Only the listed implicit conversions are allowed

Examples

Input: (['[const,&](int)->long', '[&&](int)->double'], '[const,&](int)->double')

Expected Output: True

Explanation: The first overload satisfies both required qualifiers, accepts int, and returns long which can convert to double.

Input: (['[&](int)->double'], '[&,noexcept](int)->double')

Expected Output: False

Explanation: The candidate is missing the required noexcept qualifier.

Input: (['[&&](int)->int'], '[&](int)->int')

Expected Output: False

Explanation: A target requiring '&' does not match a candidate marked only with '&&'.

Input: (['[noexcept](double)->int', '[](string)->int'], '[noexcept](int)->long')

Expected Output: True

Explanation: The first overload matches: int can convert to double, int can convert to long on return, and noexcept is present.

Input: (['[const,noexcept]()->void'], '[noexcept]()->void')

Expected Output: True

Explanation: Edge case: zero-argument callable. The target only requires noexcept, so the extra const is allowed.

Solution

def solution(signatures, target_signature):
    rank = {'bool': 0, 'int': 1, 'long': 2, 'double': 3}

    def convertible(src, dst):
        if src == dst:
            return True
        if src == 'void' or dst == 'void':
            return False
        if src in rank and dst in rank:
            return rank[src] <= rank[dst]
        return False

    def parse(sig):
        sig = ''.join(sig.split())
        end = sig.find(']')
        quals_text = sig[1:end]
        rest = sig[end + 1:]
        left, ret = rest.split('->')
        args_text = left[1:-1]
        args = [] if args_text == '' else args_text.split(',')
        quals = set(filter(None, quals_text.split(',')))
        return quals, args, ret

    def qualifiers_match(candidate, target):
        for q in ('const', 'noexcept'):
            if q in target and q not in candidate:
                return False
        if '&' in target and '&' not in candidate:
            return False
        if '&&' in target and '&&' not in candidate:
            return False
        return True

    target_quals, target_args, target_ret = parse(target_signature)

    for sig in signatures:
        quals, params, ret = parse(sig)
        if len(params) != len(target_args):
            continue
        if not qualifiers_match(quals, target_quals):
            continue
        args_ok = all(convertible(arg, param) for arg, param in zip(target_args, params))
        ret_ok = convertible(ret, target_ret)
        if args_ok and ret_ok:
            return True

    return False

Time complexity: O(N * L), where N is the number of candidate signatures and L is the average signature length. Space complexity: O(L) excluding the input storage.

Hints

  1. Treat the bracketed qualifier list as a set of properties. The target's qualifiers are requirements; the candidate may have extra ones.
  2. After qualifier matching, reuse the same argument-conversion and return-conversion logic from Part 1.
Last updated: Jun 12, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,000+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Implement a Distributed Rate Limiter - OpenAI (medium)
  • Compute Plant Infection Time - OpenAI (medium)
  • Implement IP Address Arithmetic - OpenAI (hard)
  • Simulate Infection Spread on a Grid - OpenAI (hard)
  • Implement Social Follow Recommendations - OpenAI (medium)