3

I'm trying to create some sort of comparison function that will compare certain prefixes that are known at compile time to other buffers.

I'm trying to use the predefined std::arrays that hold the prefixes as template parameters.

Here is what I tried:

constexpr std::array<std::uint8_t, 4> ARRAY_A {{0xDE, 0xAD, 0xBE, 0xEF}};
constexpr std::array<std::uint8_t, 4> ARRAY_B {{0xBA, 0xD, 0xF0, 0x0D}};

enum class Foo{
    A,B

    };

template<size_t SizeOfHeader, std::array<std::uint8_t, SizeOfHeader> Header, Foo f> 
void foo()
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

template<template<class, class> class TContainer, Foo f> 
void foo2()
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}


int main()
{
    foo2<ARRAY_A, Foo::A>();
    foo<ARRAY_A.size(), ARRAY_A, Foo::A>();
    return 0;
} 

These attempts were made after reading the following answers which seemed related: 1 , 2.

I'm interested in understanding the errors in the code as much as finding a working solution :)

Here is the failed attempt at coliru. The errors are:

main.cpp:31:5: error: no matching function for call to 'foo2'
    foo2<ARRAY_A, Foo::A>();
    ^~~~~~~~~~~~~~~~~~~~~
main.cpp:23:6: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'TContainer'
void foo2()
     ^
main.cpp:32:5: error: no matching function for call to 'foo'
    foo<ARRAY_A.size(), ARRAY_A, Foo::A>();
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:17:6: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'Header'
void foo()
     ^
2 errors generated.
2
  • @Quentin Included full error and a demo link Commented Mar 27, 2018 at 14:52
  • 1
    Perfect! ------ Commented Mar 27, 2018 at 14:53

3 Answers 3

4

You cannot pass instances of class types as template non-type parameters.

You can pass references and pointers to class types, but not instances themselves.

There has been some discussion about permitting this in a future standard revision (after ).

Your code:

template<template<class, class> class TContainer, Foo f> 
void foo2()

this takes a template template parameter, not an instance of that.

template<class, class>
class bob;

the template bob (not a class instance of it, or a value instance of a class instance of it) is a valid first template argument for foo2.

template<size_t SizeOfHeader, std::array<std::uint8_t, SizeOfHeader> Header, Foo f> 
void foo()

this is not a valid template declaration. std::array<std::uint8_t, SizeOfHeader> is going to be ill-formed there. I doubt the compiler is mandated to diagnose this error immediately, because SizeOfHeader argument to array makes the type of array dependent.

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

3 Comments

Is there a spec section forbidding that or is it just not permitted? And how would I go about sending a reference to e.g. ARRAY_A ?
@DlavimerTupin just make the parameter type a reference. Note, however, that you can only bind that parameter to static-lifetime objects with external linkage (i.e. globals and static members).
@Quentin thanks, it did not work without making the reference const which makes sense :)
3

You could pass directly the parameters using a variadic template, i.e.:

#include <type_traits>

template <typename... Ts>
typename std::enable_if<sizeof...(Ts) == 0>::type f()
{
}

template<std::uint8_t a, std::uint8_t... rest>
void f()
{
    f<rest...>();
}

See variadic function template without formal parameters for details about the base case.

Comments

1

Another way is use a constexpr function and, if you want to impose that is executed compile time, you can use it to (by example) initialize a constexpr value.

Unfortunately, you tagged C++11 so constexpr function are less flexibles.

The following is a full C++11 working example with a constexpr function that, given a couple of std::array's of the same type and dimension return the number of corresponding equal elements. The value is registered in a constexpr val variable and, moreover, checked with static_assert

#include <array>
#include <cstdint>

template <typename T, std::size_t N>
constexpr std::size_t countEqual (std::array<T, N> const & a1,
                                  std::array<T, N> const & a2,
                                  std::size_t pos = 0U,
                                  std::size_t count = 0U)
 {
   return pos < N ? countEqual(a1, a2, pos+1U,
                               a1[pos] == a2[pos] ? ++count : count)
                  : count;
 }

int main (void)
 {
   constexpr std::array<std::uint8_t, 4> ARRAY_A {{0xDE, 0xAD, 0xBE, 0xEF}};
   constexpr std::array<std::uint8_t, 4> ARRAY_B {{0xBA, 0xAD, 0xF0, 0x0D}};

   constexpr auto val { countEqual(ARRAY_A, ARRAY_B) };

   static_assert( val == 1U , "!" );
 }

Comments

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.