6

First of all, I'm sorry for the vague title of this question. I wasn't sure how to summarize it.

The thing I want to achieve is the following, I want to be able to pass template non-type parameters of different types to the same class-template, resulting in different instantiations. Something like this:

Foo<1>();
Foo<'1'>(); // different types of object

I don't think this is possible, therefore I'm forced to do something like this

template <typename T, T Val>
struct Foo;

template <int Val>
struct Foo<int, Val> 
{};

template <char Val>
struct Foo<char, Val>
{};

//...

Foo<int, 1>();
Foo<char, '1'>();

such that Foo can be specialized based upon the first template parameter. However this complicates the syntax of the mini-language I'm trying to implement in my metaprogramming framework. Is there any technique available that allows me to distinguish Foo<1> from Foo<'1'>? Basically what I want to do is set a compile-time flag (in an enum) to indicate wheter an int or char was passed, without explicitly specifying them.

EDIT The answers made me realize that my question implicates that I actually need (compile-time) instances of these objects. I don't...

Say that somehow the standard would permit me to overload a class template such that Foo<1> and Foo<'1'> are different types, and contain different values for their flag field. These types can then themselves be passed to another class template, which can inspect them and do interesting stuff with it, for example:

template <typename FooType>
struct Bar
{
    typedef typename If < FooType::flag, int, char >::Type Type;
};

This is all very easy to do when you have nothing against passing the type explicitly, but this seems superfluous...

JorenHeit
  • 3,877
  • 2
  • 22
  • 28

3 Answers3

2

You can use macro:

#define MAKE_FOO(value) \
    Foo<decltype(value), value>()

Actually, I think you need something like widespread function template make_something at compile-time. Unfortunately, I don't know how to implement it.

Constructor
  • 7,273
  • 2
  • 24
  • 66
  • I was afraid of this being the only answer. Of course I already considered this option, but macro's are evil ;-) Will mark as answer if no-one has a better idea. – JorenHeit Jan 10 '14 at 16:51
  • Whats about the same approach but with default template parameters? `template` But somehow im sure this wont compile :D – Sebastian Hoffmann Jan 10 '14 at 16:56
  • 1
    @Paranaix it wouldn't work because default parameters need to be filled from the right. – mpark Jan 10 '14 at 16:57
  • I ended up writing a macro to hide the ugly stuff from the end-user, even though this is very bad style... Marked as answer! – JorenHeit Jan 11 '14 at 12:49
1

If you simply need the values available at compile-time but don't actually need them as part of the type, (As in, if you don't need Foo<int, 1> and Foo<int, 2> to be different types) then you can use a constexpr constructor along with a constexpr function to give rise to Foo instances at compile-time.

#define DECLTYPE_AUTO(expr) \
  -> decltype(expr) { return expr; }

template <typename T>
struct Foo {

  constexpr Foo(T t) : value(t) {}

  T value;

};  // Foo

template <typename T>
constexpr auto MakeFoo(T val)
    DECLTYPE_AUTO(Foo<T>(val));

static_assert(MakeFoo(2).value == 2, "");
static_assert(MakeFoo('1').value == '1', "");

int main() {}
mpark
  • 7,574
  • 2
  • 16
  • 18
  • Interesting... However I think it's not of much use to me. My fault entirely for not stating enough details in the question. Question edited :-) – JorenHeit Jan 10 '14 at 17:24
0

You could do something like this:

template <int Val>
struct Foo<int, Val> 
{
    static MyEnum tag = myTag1;
};


template <char Val>
struct Foo<char, Val>
{
    static MyEnum tag = myTag2;
};
Kit Fisto
  • 4,385
  • 5
  • 26
  • 43
  • And the purpose is what? – Sebastian Hoffmann Jan 10 '14 at 16:38
  • Distinguish Foo<1> from Foo<'1'>? – Kit Fisto Jan 10 '14 at 16:40
  • You still have to pass either `int` or `char` to `Foo`, which is exactly what I want to avoid. I want the compiler to deduce the type, like it does with function overloading. The [post](http://stackoverflow.com/q/9400581/212858) by Useless is about exactly the same problem, and it was then concluded that it's not possible... – JorenHeit Jan 10 '14 at 16:42
  • Sure it is not possible. Therefore I thought the above approach could help you with your idea and simplify your life. – Kit Fisto Jan 10 '14 at 16:45
  • This is exactly what I already did in my opening post. If that had been satisfactory, I wouldn't have asked in the first place. – JorenHeit Jan 10 '14 at 16:46
  • I got your question wrong. Your problem is instantiation of the instances not distinguishing them afterwards. Sorry. – Kit Fisto Jan 10 '14 at 16:55
  • @KitFisto Yup! No problem :-) – JorenHeit Jan 10 '14 at 17:11