简体   繁体   中英

How can I use iterator values in templates?

Consider the following code:

#include <iostream>

enum class E
{
    A,
    B
};

template<E e> int f();

template<> int f<E::A>(){ return 1; }
template<> int f<E::B>(){ return 2; }

int main()
{
  for( const E i : {E::A, E::B} )
  {
      std::cout << f<i>() << "\n";
  }
}

This fails to compile, because i is not initialised with a constant expression. Is it possible make this idea of a code work?

This is very related: Why isn't a for-loop a compile-time expression? .

i in your loop is not a constant expression. However, by stealing from this answer one can make your code call f<i> inside the loop. It is not directly what you asked for because the proposed solution is for size_t index based loops instead of iterators, but it does call f<i> for all values of the enum:

#include <iostream>
#include <utility>

// your code

enum class E
{
    A,
    B
};

template<E e> int f();

template<> int f<E::A>(){ return 1; }
template<> int f<E::B>(){ return 2; }

// https://stackoverflow.com/a/47563100/4117728

template<std::size_t N>
struct num { static const constexpr auto value = N; };

template <class F, std::size_t... Is>
void for_(F func, std::index_sequence<Is...>)
{
  using expander = int[];
  (void)expander{0, ((void)func(num<Is>{}), 0)...};
}

template <std::size_t N, typename F>
void for_(F func)
{
  for_(func, std::make_index_sequence<N>());
}

// emulate constexpr for (size_t i=0;i<2;++i) f<i>();    

int main()
{
  for_<2>([&] (auto i) {      
    std::cout << f<static_cast<E>(decltype(i)::value)>();
  });
}

Output :

12

Probably there is a simpler solution for your actual problem. The answer to your literal question is: No. You cannot call f<i> when i is not a compile time constant. For detailed explanation I refer you to the above mentioned q&a.

The compiler is not able to deduce i in the call to f<i>() . This is because compilation happens before runtime, and the value of i is only available during runtime. You can work around this by adding a translator.

#include <iostream>

enum class E
{
    A,
    B
};

template<E e> int f();

template<> int f<E::A>(){ return 1; }
template<> int f<E::B>(){ return 2; }

int bar(E e)
{
  int retval = 0;
  switch(e)
  {
    case E::A:
    {
      return f<E::A>();
      break;
    }
    case E::B:
    {
      return f<E::B>();
      break;
    }
    default:
    {
      break;
    }
  }
  return retval;
}

int main()
{
  for( const E i : {E::A, E::B} )
  {
      std::cout << bar(i) << "\n";
  }

  return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM