1

The C++17 standard mentions a peculiar variadic function template that

  • takes no normal function arguments but, instead,
  • takes nontype template arguments,

like f<200, 50, 6>() == 256.

I thought, that's odd, let me see if I can code that myself. My code was elegant. My elegant code however would not compile, so after two fruitless hours I wrote this ugly code:

#include <iostream>

namespace {
    template<int A> constexpr int f() {return A;}
    template<int A, int B, int... C> constexpr int f() {
        if (sizeof...(C)) return A + f<B, C...>();
        else return A + B;
    }
}

int main() {
    int n = f<200, 50, 6>();
    std::cout << n << "\n";
    return 0;
}

This ugly code worked, and it was fun because it incidentally taught me sizeof...(). It cannot be right, though, can it?

Every time I try something simpler, the compiler balks, complaining about name-lookup conflicts or template redefinitions or something else of the kind.

My concept feels wrong. I suspect that I have missed the point. What point have I missed, please?

REFERENCE

For information, in the standard (draft here), the section that has provoked my question is sect. 5.13.8 (paragraphs 3 and 4). However, as far as I know, the provocation was incidental. My question is not about the standard as such. My question is about the proper, elegant use of variadics, rather.

NONCOMPILING EXAMPLE

If you want an example of my more elegant, noncompiling code, here is one:

namespace {
    template<> constexpr int f() {return 0;}
    template<int A, int... C> constexpr int f() {
        return A + f<C...>();
    }
}

After reading the compiler's error message, I understand why this particular code fails, so that is not my question. My question, rather, is

  • how a variadic call like f<200, 50, 6>() ought properly to have been implemented and
  • what concept I am consequently missing regarding C++ variadics.
3
  • 1
    Not sure what is asked here. If you understand why your code is not well-formed, and what well-formed code looks like, what are you asking about? Commented Mar 7, 2019 at 21:49
  • @SergeyA I doubt that I am using the variadic as the makers of C++ meant it to be used. If I am doing it right, after all, please tell me. Commented Mar 7, 2019 at 21:52
  • Two close votes for unclear what I'm asking! That's too bad. I worked on the question for over an hour before posting it, so that's about the best I can do. Oh, well. Commented Mar 7, 2019 at 21:59

1 Answer 1

5

The C++17 way to write the function is

template<auto... Vals>
constexpr auto sum() noexcept(noexcept((Vals + ...)))
{
    return (Vals + ...);
}

Where template<auto... Vals> says we have a variadic template of values and (Vals + ...) is a fold expression which adds all of the values together (the outer () are required to make a valid fold expression).

I used auto... so that it isn't limited to a specific type. SFINAE can be added to constrain the template to only types that support addition if that is needed otherwise you'll just get a compiler error if not all types in the parameter pack can be added together.

Sign up to request clarification or add additional context in comments.

6 Comments

I like your noexcept :)
Yes, you understood my question. Your code is better. Now you have me thinking whether an operator like operator+() is really necessary to use your technique, or whether something like foo(Vals, ...) would likewise work. Now that you have pointed me in the right direction, I will study it.
@thb foo(Vals, ...) should be foo(Vals...). In that context it makes it a comma separated list. In a fold expression like I use special rules apply to make the operator used expand out the pack, instead of commas like you would normally get.
@SergeyA Isn't it exceptional ;) (couldn't help myself)
@thb cppreference has a lot of good information that has helped me and just reading a lot of stuff on SO and blogs. Also cppcon videos (they are free on youtube). They run a great conference and the videos are quite informative.
|

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.