0

How can I achieve in the below code that the compiler will return the intended compilation error message from the assertion in mixer (cf option B)?

#include<iostream>
#include<type_traits>

template<typename _T>
struct Base{
    using T=_T;
};

template<typename _T>
struct Derived: Base<_T>{};

template<typename _T>
struct Underived{};

template<typename Q, typename P>
struct Tumbler{};

// CODE OPTION A
template<typename TDerived>
using Mixer = Tumbler<TDerived,typename TDerived::T>;

// CODE OPTION B
template<typename TDerived>
struct Mixer: Tumbler<TDerived,typename TDerived::T>{
    static_assert(std::is_convertible<TDerived*, Base<typename TDerived::T>*>::value, "TDerived must be derived of Base");
};

int main(){
    Mixer<  Derived<float>> mixer_intend;
    Mixer<Underived<float>> mixer_misuse; // spits error: "T undefined". I want error "is not derived of base"
    std::cout << "passed\n";
}

The issue at hand is that a meaningful assertion of inheritance cannot be posed without knowledge on the type T. Solutions along option A are preferred over solutions along option B.

Application Context

A user may call a SolverFactory for a Derived of an Original Problem instead of a Preprocessed Problem. A solution to the above problem would allow me to hint the user that he/she/it forgot to preprocess the problem first and pass it afterwards. Now instead, the user will look into his/her/its problem to fruitlessly find an error therein.

2
  • Which C++ standard does your compiler support? Commented Aug 25, 2023 at 11:50
  • @康桓瑋 std=c++20 would be nice, but generally I am open. Thank you for asking. Commented Aug 25, 2023 at 12:09

2 Answers 2

0

The issue at hand is that a meaningful assertion of inheritance cannot be posed without knowledge on the type T.

In C++20 you can define concepts as

template<typename Derived>
concept derived_from_base = requires (const Derived& d) {
  []<typename T>(const Base<T>&){}(d);
};

which requires that an object of type Derived can be passed into a lambda that only accepts parameters of a specialized Base class, which can be used to determine whether the type Derived is public and unambiguous inherits from a template class Base.

Then you can constrain the using type-alias as

template<derived_from_base TDerived>
using Mixer = Tumbler<TDerived, typename TDerived::T>;

Demo

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

Comments

0

You can use std::is_base_of:

static_assert(std::is_base_of_v<Base<typename TDerived::T>, TDerived>,
              "TDerived must be derived of Base");

You can also define a concept such as:

template<typename TDerived>
concept Mixer = std::derived_from<T, Base<typename TDerived::T>>;

This concept can then be used as a type constraint rather than putting a static_assert into your class.

Comments

Your Answer

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