3

As I know how to pass template function as template argument, I'm now struggling to pass variable template in a similar manner.

Here is minimal example of what I tried:

#define PASS_VARIABLE_TEMPLATE(name) [dummy=nullptr](auto&&...args) \
                                                    {return name<decltype(args)...>;}

//testing
template <typename T>
bool value = std::is_fundamental<T>::value;

template <typename Hax>
void print_bool(Hax h)
{
    std::cout << h(int{}) << std::endl; // no error, wrong output
    //std::cout << h(int{}, float{}) << std::endl; // error, good
}

int main()
{
    print_bool(PASS_VARIABLE_TEMPLATE(value)); //prints 0 instead of 1
}

Demo

If it compiles, then why the output is wrong?

4
  • Is a reference good enough? Commented Oct 9, 2016 at 15:04
  • @lorro Oh silly me, forgot to do the decaying! But on other hand that would destroy reference/pointer checking... It should be possible to check this case too: int b; int& ref = a; h(ref); //type is int& Commented Oct 9, 2016 at 15:05
  • You will get the expected results with #define PASS_VARIABLE_TEMPLATE(name) [dummy=nullptr](auto&&args) { return name<typename std::remove_reference<decltype(args)>::type>; } Commented Oct 9, 2016 at 15:12
  • @SamVarshavchik Yes, but on the other hand if std::is_rvalue_reference was applied instead, wouldn't it break? Commented Oct 9, 2016 at 15:15

2 Answers 2

3

The main problem with your code is that decltype deduces the arguments as an rvalue reference (int&&) because your lambda uses forwarding references to accept the arguments. std::is_fundamental will work well with a bare type.

For your specific snippet, the correct solution is to remove the reference.

#define PASS_VARIABLE_TEMPLATE(name) \
    [dummy=nullptr](auto&&...args){return name<std::remove_reference_t<decltype(args)>...>;}

Now it works. :-) See it Live On Coliru


A slightly more or better generic way will be to additionally remove cv qualifiers. In the end, you may want to use std::decay

#define PASS_VARIABLE_TEMPLATE(name) [dummy=nullptr](auto&&...args) \
{return name<std::decay_t<decltype(args)>...>;}
Sign up to request clarification or add additional context in comments.

Comments

1
template<class T>struct tag_t{using type=T; constexpr tag_t(){}};
template<class Tag>using tagged_type=typename Tag::type;
template<class T>constexpr tag_t<T> tag{};

These help pass types as values and unpack them.

#define PASS_VARIABLE_TEMPLATE(name) [](auto...args) \
                                                {return name<tagged_type<decltype(args)>...>;}

Inside print_bool you do:

std::cout << h(tag<int>) << std::endl;

Not sure why you do the dummy=nullptr thing.

tag as a template can carry types unmolested.

1 Comment

dummy is due to GCC bug with non-capturing lambda (check out the accepted answer from link I posted in the question). Btw, great solution.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.