2

I need to select between two types for a variable at compile time. One of these types have a concept requirement which is not always satisfied and that is when I want to select the other type. I am trying to achieve this with std::conditional_t, but both types to std::conditional are evaluated causing a template constraint failure.

Here's a minimal example:

#include <concepts>

template <typename T> requires std::same_as<T, int>
struct Foo {};

using MyType1 = std::conditional_t<true, int, Foo<int>>; // Compiles
using MyType2 = std::conditional_t<false, int, Foo<int>>; // Compiles
using MyType3 = std::conditional_t<true, int, Foo<double>>; // Doesn't compile (constraint fails)
using MyType4 = std::conditional_t<true, Foo<double>, int>; // Doesn't compile (constraint fails)

MyType3 and 4 both fails since Foo does not satisfies the constraint on Foo. For MyType3 I would expect it to work since the conditional selects int as the type, not Foo.

Can I achieve my goal with std::conditional or any other means?

1
  • Hint: the concept cam be incorporated into the template, like template <std::same_as<int> T>. Commented Jun 7, 2024 at 7:16

2 Answers 2

6

You might add some indirection:

template <template <typename> class C, typename T>
struct binder
{
    using type = C<T>;
};

using MyType3 = std::conditional_t<true,
                                  std::type_identity<int>,
                                  binder<Foo, double>>::type;

Demo

Sign up to request clarification or add additional context in comments.

Comments

0

Jarod42's answer is good, but I also found another possible solution using template specialization which I post here for completeness sake:

#include <concepts>

template <std::same_as<int> T>
struct Foo {};

template <bool T>
struct MyConditional {
    using type = int;
};

template <>
struct MyConditional<false> {
    using type = Foo<int>;
};

using MyType3 = MyConditional<true>::type;
static_assert(std::is_same_v<MyType3, int>);

using MyType4 = MyConditional<false>::type;
static_assert(std::is_same_v<MyType4, Foo<int>>);

2 Comments

You no longer have Foo<double> anywhere ;-)
@Jarod42 True, but this solves the overall problem where I want either an int or a Foo<int> based on the truth value which in my real case would be a type check. The original minimal example is not very well constructed as the Foo<double> is a bit artificial.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.