aliassing a template parameter pack - c++

I would like to use a using alias for a parameter pack such that the templates can be used elsewhere in the code base. In the following code I commented the lines where I would use the types:
template <typename FirstArg, typename ... OtherArgs>
struct Base {
using UsableFirstArg = FirstArg;
// this would be needed later
// using UsableOtherArgs... = OtherArgs...;
virtual OtherClass method(OtherArgs... a) = 0
};
template <typename DerivedOfBaseInstantiation>
struct CallerStructure {
// to be used here
// OtherClass unknownCall(typename DerivedOfBaseInstantiation::UsableOtherArgs... args) {
// DerivedOfBaseInstantiation instance;
// return instance.method(args...);
// }
}
At code write time of CallerStructure, the arguments of unknownCall are not known and are determined by the instantiation of CallerStructure where DerivedOfBaseInstantiation is a type that's derived of Base. In a more complete example that would look like that:
class OtherClass {
};
template <typename FirstArg, typename ... OtherArgs>
struct Base {
using UsableFirstArg = FirstArg;
using UsableOtherArgs... = OtherArgs...;
virtual OtherClass method(OtherArgs... a) = 0;
};
struct Derived_df : Base<int, double, float> {
OtherClass someMethod(Base::UsableFirstArg); // int
OtherClass method(double, float) override ;
};
template <typename DerivedOfBaseInstantiation>
struct CallerStructure {
OtherClass knownCall(typename DerivedOfBaseInstantiation::UsableFirstArg a) {
DerivedOfBaseInstantiation instance;
return instance.someMethod(a);
}
OtherClass unknownCall(typename DerivedOfBaseInstantiation::UsableOtherArgs... args) {
DerivedOfBaseInstantiation instance;
return instance.method(args...);
}
};
void instantiations() {
CallerStructure<Derived_df> c;
[[maybe_unused]] auto a = c.knownCall(42);
[[maybe_unused]] auto b = c.unknownCall(23., 11.f);
}
Any hints of how to access the variadic templates of Base for the method interface in CallerStructure?
mandatory compiler-explorer link

You cannot alias variadic template argument. You can wrap them in std::tuple:
template <typename FirstArg, typename ... OtherArgs>
struct Base {
using UsableFirstArg = FirstArg;
using UsableOtherArgs = std::tuple<OtherArgs...>;
virtual OtherClass method(OtherArgs... a) = 0;
};
Unwrapping need some helpers:
template <typename DerivedOfBaseInstantiation,
typename = typename DerivedOfBaseInstantiation::UsableOtherArgs>
struct CallerStructure;
template <typename DerivedOfBaseInstantiation, typename ... OtherArgs>
struct CallerStructure<DerivedOfBaseInstantiation, std::tuple<OthersArgs...>> {
OtherClass knownCall(typename DerivedOfBaseInstantiation::UsableFirstArg a) {
DerivedOfBaseInstantiation instance;
return instance.someMethod(a);
}
OtherClass unknownCall(OtherArgs... args) {
DerivedOfBaseInstantiation instance;
return instance.method(args...);
}
};

Related

derived class as a parameter of templated function which is specialized for its base class

class Base {};
class Derived : public Base {};
class SomeClass
{
template<typename T>
static void SetContent(T* pChild, OVariant content)
{
LOG_ASSERT(0, "All classes must be specialized!. Please provide implementation for this class.");
}
};
template <>
void SomeClass::SetContent(Base* value)
{
LOG_TRACE("Yay!");
}
int main() {
SomeClass foo;
Derived derived;
foo.SetContent(&derived);//want it to call SomeClass::SetContent(Base* value)
return 0;
}
When I call foo.SetContent(derived), I get the Assert. Is it not possible for the derived class to use the specialization for it's base class?
You can convert a Derived* to a Base*, but I think you rather want to specialize for all T that have Base as base
#include <type_traits>
#include <iostream>
class Base {};
class Derived : public Base {};
template <typename T,typename = void>
struct impl {
void operator()(T*) {
std::cout <<"All classes must be specialized!. Please provide implementation for this class.\n";
}
};
template <typename T>
struct impl<T,std::enable_if_t<std::is_base_of_v<Base,T>>> {
void operator()(T*) {
std::cout << "Yay\n";
}
};
class SomeClass
{
public:
template<typename T>
static void SetContent(T* pChild)
{
impl<T>{}(pChild);
}
};
struct bar{};
int main() {
SomeClass foo;
Derived derived;
foo.SetContent(&derived);
bar b;
foo.SetContent(&b);
}
Output:
Yay
All classes must be specialized!. Please provide implementation for this class.
//want it to call SomeClass::SetContent(Base* value)
Note that if the template argument is deduced, it will be deduced as Derived not as Base and the argument is Derived*. SomeClass::SetContent<Base>(&derived); would already work as expected with your code (because Derived* can be converted to Base*).
A workaround would be to have all SetContent's explicit specializations to form an overload set. You will have to do it yourself:
#include <iostream>
#include <utility>
#include <functional>
class Base {};
class Derived : public Base {};
template <class... T>
struct Overloads : T... {
Overloads(const T &... t) : T(t)... {}
using T::operator()...;
};
template <class R, class... Args>
struct FunctionP {
using F = R(Args...);
FunctionP(F *t) : t_(t) {}
R operator()(Args... args) const {
return std::invoke(t_, std::forward<Args>(args)...);
}
F *t_;
};
struct SomeClass {
template<typename T>
static void SetContent(T *x) {
Overloads o(FunctionP(&SetContentImpl<Base>)); // enumerates all the specializations here
if constexpr (std::is_invocable_v<decltype(o), T *>) {
o(x);
} else {
SetContentImpl(x);
}
}
template<typename T>
static void SetContentImpl(T *) {
std::cout << "1";
}
};
template <>
void SomeClass::SetContentImpl(Base *) {
std::cout << "2";
}
int main() {
SomeClass foo;
Derived derived;
foo.SetContent(&derived);//want it to call SomeClass::SetContent(Base* value)
return 0;
}
godbolt

factory creating different types according to enum values c++

I have some auto generated structs each logically related to a enum value.
can I create a factory using a template function?
everything can be resolved at compiled time.
I tried something like this:
struct Type1
{
};
struct Type2
{
};
enum class type_t
{
first,
second
};
template <type_t typet>
auto Get_()
{
static_assert(typet == type_t::second);
return Type2();
}
template <type_t typet>
auto Get_()
{
static_assert(typet == type_t::first);
return Type1();
}
template <type_t typet>
auto Get_()
{
static_assert(false, "no overload");
}
int main()
{
auto relatedType1 = Get_<type_t::first>();
auto relatedType2 = Get_<type_t::second>();
}
In C++11 (and above), you may use an auxiliary traits struct like the following:
template <type_t T>
struct type_selector;
template <>
struct type_selector<type_t::first> {
using type = Type1;
};
template <>
struct type_selector<type_t::second> {
using type = Type2;
};
// implement other specializations, if needed
Then, your Get_ function template is simply:
template <type_t typet>
auto Get_() -> typename type_selector<typet>::type {
return {};
}

Is it possible to deduct the template type of a templated parameter in C++?

I have a template class, with an internal method that is itself templated.
Consider the following minimal working example
#include <functional>
template<typename T>
class P{
public:
template <typename U>
P<U> call(std::function< P<U> (T)> f){
return f(return_value);
}
T return_value;
};
P<int> foo() {
P<int> value = P<int>();
return value;
}
P<float> bar(int arg) {
return P<float>();
}
int main()
{
auto res = foo().call<float>(bar);
return 0;
}
As you can see in the main function, the compiler forces me to to specify the float type for calling the call() function, eventhough the type should be obvious from passing over the bar() function, that specifies the float type.
Is it somehow possible to deduct the type so that the code in the main function can be simplified to the following statement:
auto res = foo().call(bar);
std::function is not the type that you should use whenever you want to pass a function around. std::function is a type that uses type erasure to be able to store different types of callables in one type. If you don't need that then you need no std::function:
#include <functional>
template<typename T>
class P{
public:
template <typename F>
auto call(F f){
return f(return_value);
}
T return_value{}; // don't forget to initialize !
};
P<int> foo() {
P<int> value = P<int>();
return value;
}
P<float> bar(int arg) {
return P<float>();
}
int main()
{
auto res = foo().call(bar);
return 0;
}
Using partial specializatzion you can get the return type of bar and you can get the float from P<float>:
#include <type_traits>
#include <iostream>
template <typename T> class P;
// get return type from function
template <typename T> struct return_type;
template <typename R,typename...args>
struct return_type<R(args...)> { using type = R; };
// get T from P<T>
template <typename P> struct P_arg;
template <typename T> struct P_arg< P<T> > { using type = T; };
// combine both
template <typename F>
struct get {
using type = typename P_arg<typename return_type<F>::type >::type;
};
template<typename T>
class P{
public:
template <typename F>
auto call(F f){
return f(return_value);
}
T return_value{};
};
P<float> bar(int arg) {
return P<float>();
}
int main()
{
std::cout << std::is_same_v< get<decltype(bar)>::type,float>;
return 0;
}
Though that does not really help here, because you cannot use it to decalre the return type of P::call, as it requires P<float> to be already complete.

Accessing functions of a derived crtp class from the base calls

I need to be able to access a static method of the derived class, from within a base CRTP class. Is there a way in which I can achieve this?
Here is example code:
#define REQUIRES(...) std::enable_if_t<(__VA_ARGS__), bool> = true
template<typename Derived>
struct ExpressionBase {
Derived& derived() { return static_cast<Derived&>(*this); }
const Derived& derived() const { return static_cast<const Derived&>(*this); }
constexpr static int size()
{
return Derived::size();
}
template<typename T, REQUIRES(size() == 1)>
operator T() const;
};
struct Derived : public ExpressionBase<Derived>
{
constexpr static int size()
{
return 1;
}
};
Deriving from ExpressionBase<Derived> involves the instantiation of ExpressionBase<Derived>, therefore involves the declaration of the entity
template<typename T, REQUIRES(size() == 1)>
operator T() const;
Here, std::enable_if_t got a template argument that is ill-formed (because Derived isn't complete yet). The SFINAE rule does not apply here, because the ill-formed expression is not in direct context of template argument type, thus it is treated as a hard error.
In order to make the ill-formation happen at an immediate context, use the following code:
#include <type_traits>
template <bool B, class T>
struct lazy_enable_if_c {
typedef typename T::type type;
};
template <class T>
struct lazy_enable_if_c<false, T> {};
template <class Cond, class T>
struct lazy_enable_if : public lazy_enable_if_c<Cond::value, T> {};
template <class T>
struct type_wrapper {
using type = T;
};
#define REQUIRES(...) std::enable_if_t<(__VA_ARGS__), bool> = true
template<typename Derived>
struct ExpressionBase {
Derived& derived() { return static_cast<Derived&>(*this); }
const Derived& derived() const { return static_cast<const Derived&>(*this); }
struct MyCond {
static constexpr bool value = Derived::size() == 1;
};
template<typename T, typename = typename lazy_enable_if<MyCond, type_wrapper<T>>::type>
operator T () const {
return T{};
}
};
struct Derived : public ExpressionBase<Derived>
{
constexpr static int size() {
return 1;
}
};
int main() {
Derived d;
int i = d;
return 0;
}
It is actually adapted from boost, which you can find more details here.

Declaring a function with same signature of the given template parameter's function

I'm writing a wrapper class to be derived which hides the implementation. How can I get the signature of the given template parameter's function?
template <class T>
struct wrapper
{
static typename std::result_of<&T::impl>::type
call(...) { // this function has the same signature of T::impl();
// here goes the jobs to do, such as logging or something
return T::impl(...);
}
};
struct sum : public wrapper<sum>
{
private:
friend class wrapper<func>
static int impl(int a, int b, int c) {
return a + b + c;
}
};
int main()
{
bind_to(&sum::call); // set binding
std::cout << sum::call(1,2,3) << std::endl;
}
Use a parameter pack:
template <class T>
struct wrapper
{
template <typename... Args>
auto call(Args&&... args) -> decltype(T::impl(std::forward<Args>(args)...))
{
return T::impl(std::forward<Args>(args)...);
}
};