Question

Assume that the parameters of functions representing operations of the relational algebra are represented by individual types: structs or classes. An operation such as (natural) join will have parameters of two types (T1, T2) as inputs and produce a return value of a third type (T3). There is a relationship between types T1, T2 and T3 which can in theory be known and checked at compile time. Is there a way to do that using C++ templates?

Example: assume these input types (the CJDate supplier data):

struct supplier {
  string sid;
  string sname;
  integer status;
  string city;
}
struct supplierpart {
  string sid;
  string pid;
  integer qty;
}

This is the output type:

struct ssp_join {
  string sid;
  string pid;
  integer qty;
  string sname;
  integer status;
  string city;
}

Is there any strategy that would (say) allow the output type to be generated from the inputs using templates and thus be statically type checked?

Disclosure: I'm an experienced C++ programmer and I currently have no idea how to either solve this problem or prove that it can't be done. A solution in some other language would be equally interesting.


After some further investigation, it seemed to me that key missing feature might be the kind of metaprogramming that means the ability to execute arbitrary code at compile time, prior to type resolution. The D language seems to have that. I wonder if the C++ committee are considering it.

Was it helpful?

Solution

What you're talking about will not be directly possible in C++ until we get some form of both reflection introspection and reflection-based generation of types. So you're going to have to wait for a while.

The closest you can get right now is to employ inheritance:

template<typename T1, typename T2>
struct joined : public T1, public T2
{
};

Of course, this would cause you to have two separate sid members.

Indeed, most of the current attempts at solutions (tuple typelist concatenation) run into that same problem: how to remove duplicate entries.

You could do it with tuple concatenation if you used some special tag applied to each tuple element to give it a "name" of some kind. You could do that with something like this:

template<typename T, typename TagType>
struct tagged_type
{
  T t;
  using Tag = TagType;
};

//Various tag names
struct sid{};
struct sname{};
struct status{};
struct city{};
struct pid{};
struct qty{};

using supplier = tuple<
  tagged_type<std::string, sid>,
  tagged_type<std::string, sname>,
  tagged_type<int, status>,
  tagged_type<std::string, city>>;

using supplierpart = tuple<
  tagged_type<std::string, sid>,
  tagged_type<std::string, pid>,
  tagged_type<int, qty>>;

You can even make an alternate form of std::get that works by tag-name, to make it easier to access the tuple: get<sid>(tpl) and so forth.

From here, you then have to do a very complicated bit of metaprogramming where you concatenate the two tuples, but without duplicating entries.

Licensed under: CC-BY-SA with attribution
scroll top