Home > Enterprise >  C detect if a type can be called with a template type
C detect if a type can be called with a template type

Time:11-24

I'm working on a program where some data is statically allocated and some is dynamically allocated. Now I want to have another type that can be called with any template of the type as its argument.

#include <array>
#include <vector>
template <int size> class Foo {
  std::array<int, size> data;
public:
  int& operator[](std::size_t idx) {return data[idx];}
};
template <> class Foo<-1> {
  std::vector<int> data;
public:
  int& operator[](std::size_t idx) {return data[idx];}
};
// option 1- polymorphism
struct FooCaller {
  virtual void operator()(Foo data) = 0; // how would I make this work with both forms of Foo?
};
// option 2- generic programming
template <class T> concept CanCallFoo = requires (const T& t) {
  t(std::declval<Foo&>()); // how do I ensure that this can call any overload of Foo?
};

Both methods would be fine, but I'm not sure how to go about this. Because the full code is more complex, I'd rather not have both Foos inherit from a base.

CodePudding user response:

A callable F could write a restriction that it can be called by Foo<x> such that an arbitrary function of x must be true to be valid.

In order for your "can be called with any Foo" test to work, you would have to invert an arbitrary function at compile time.

There is no practical way to do this short of examinjng all 2^32 possible values of x. No, really. The problem you have is that the type F is possibly too powerful for you to determine its properties. This is related to Halt and Rice's theorem and the fact that template metaprogramming and C overload resolution is Turing complete (only related, because 2^32 is finite).

In the other case, you could type erase. Write a type RefAnyFoo/AnyFooValue that can be constructed from any Foo type and "type erases" the operations you want, like how std::function<void(int)> type erases. It could either duck type the Foo or actually restrict to instsnces of types made from the template.

Then your interface is one that takes a AnyFooValue/RefAnyFoo (depending if you are talking about copies or references).

Now, flipping this over, you can write a concept that accepts F that take RefFooAny. This isn't quite what you asked for, but plausibly you have an X/Y problem; you had a real problem, came up with incomplete solutions, then asked about how to get your solutions working, instead of the original problem.

Similarly, it is possible you only care about certain ducktype properties of Foo<?> and not the specific type. Then a concept that checks those ducktypes could be used by your callable; this again deosn't solve your problem, as much as it flips it upside down, because you cannot verify a callable accepts an entire concept from outside the callable.

  • Related