template metaprogrammingNewTupleType_ not compiling

I have errors in the following:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
template<typename TVal, size_t N, size_t M, typename TProcessedTypes, typename ...TRemainTypes>
struct NewTupleType_;


template<typename TVal, size_t N, template<typename...> class TCont, typename ...TModifiedTypes, typename TCurType, typename ...TRemainTypes>
struct NewTupleType_<TVal, N, N, TCont<TModifiedTypes...>, TCurType, TRemainTypes...>
	{
		using type = TCont<TModifiedTypes..., TVal, TRemainTypes...>;
	};

template<typename TVal, size_t N, size_t M,
	template<typename...> class TCont,
	typename ...TModifiedTypes,
	typename TCurType,
	typename ...TRemainTypes>
struct NewTupleType_<TVal, N, M, TCont<TModifiedTypes...>, TCurType, TRemainTypes...>
	{
		using type = typename NewTupleType_<TVal, N, M + 1, TCont<TModifiedTypes..., TCurType>, TRemainTypes...>::type;
	};


template<typename TVal, size_t TagPos, typename TCont, typename...TRemainTypes>
         using NewTupleType = typename NewTupleType_<TVal, TagPos, 0, TCont, 
         TRemainTypes...>::type;


When called by this code I get errors:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
	template <typename Tag, typename Head, typename... Tail>
	constexpr size_t Tag2ID()
	{
		if constexpr (sizeof...(Tail))
			return std::is_same_v<Tag, Head> ? 0 : 1 + Tag2ID<Tag, Tail...>();
		else
			return 1;
	}

	struct NullParameter;


	template<typename ...TParameters>
	struct VarTypeDict
	{
		template<typename...TTypes>
		struct Values
		{
			Values() = default;

			Values(std::shared_ptr<void>(&& input)[sizeof...(TTypes)])
			{
				for (size_t i = 0; i < sizeof...(TTypes); ++i)
				{
					m_tuple[i] = std::move(input[i]);
				}
			}


			template<typename TTag, typename TVal>
			auto Set(TVal&& val)&&
			{
				constexpr static size_t TagPos = Tag2ID<TTag, TParameters...>();

				using rawVal = std::decay_t<TVal>;
				rawVal* tmp = new rawVal{ std::forward<TVal>(val) };
				m_tuple[TagPos] = std::shared_ptr<void>(tmp, [](void* ptr)
					{
						rawVal* nptr = static_cast<rawVal*>(ptr);
						delete nptr;
					});
				using new_type = NewTupleType<rawVal, TagPos, Values<>, TTypes...>;
				return new_type{ std::move(m_tuple) };

			}

			template<typename TTag>
			const auto& Get() const;
		private:
			std::shared_ptr<void>   m_tuple[sizeof...(TTypes)];
		};

	public:
		static auto Create()
		{
			using type = typename Create_<sizeof...(TParameters), Values>::type;
			return type{};
		}
	};

}

struct A;
struct B;
struct C;

void useVarTypeDict()
{
	VarTypeDict<A, B, C>::Create().Set<A>(true).Set<B>(1.55).Set<C>(60000L);
}


I get these errors:


use of undefined type 'NewTupleType_<TVal,3,3,VarTypeDict<A,B,C>::Values<TCurType,double,NullParameter>>'


signaling the error in the using in this code:


1
2
3
4
5
6
7
8
9
template<typename TVal, size_t N, size_t M,
		template<typename...> class TCont,
		typename ...TModifiedTypes,
		typename TCurType,
		typename ...TRemainTypes>
	struct NewTupleType_<TVal, N, M, TCont<TModifiedTypes...>, TCurType, TRemainTypes...>
	{
		using type = typename NewTupleType_<TVal, N, M + 1, TCont<TModifiedTypes..., TCurType>, TRemainTypes...>::type;
	};



I know there must be a simple mistake but I am stuck
Any help appreciated...

Thanks
Hi

I don't know enough to help you, but:

Have you tried http://www.metashell.org/ ?
Looks like the usage of NewTupleType on line 42 can be replaced entirely with
Values<TTypes...>
Line 42 had a typo anyway:
using new_type = NewTupleType<rawVal, TagPos, Values<>, TTypes...>;
Because Values<> is a template type argument but I think you wanted to pass a template template argument instead.

VarTypeDict::Values::Set
is overly complicated, because this compiles and is safe:
std::shared_ptr<void> p = std::make_shared<int>(32);

That being said, there's no reason to throw away the type of the pointed-to object using void*, because you're forced to return a different type anyway. If necessary the caller can always pass std::any as the argument to Set.

Finally I'm not 100% sure what you're trying to do, but hopefully this example will help.
The core idea is the same: associate types to values by converting the type to a number n, and then accessing the nth member of some tuple.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <string>
#include <iostream>
#include <type_traits>
#include <tuple>

using namespace std::literals;

template <typename Tag, typename Head, typename... Tail>
  constexpr size_t Tag2ID()
  {
    if constexpr (sizeof...(Tail))
      return std::is_same_v<Tag, Head> ? 0 : 1 + Tag2ID<Tag, Tail...>();
    else
      return std::is_same_v<Tag, Head> ? 0 : 1;
  }

  
template <typename = std::tuple<>, typename = std::tuple<>> struct type_value_map;
template <typename... Ks, typename... Vs> 
  struct type_value_map<std::tuple<Ks...>, std::tuple<Vs...>>
  {
    std::tuple<Vs...> data;
  
    template <typename K, typename V> 
      type_value_map<std::tuple<Ks..., K>, std::tuple<Vs..., V>> append(V v) 
      { // aggregate initialization for brevity only:
        return {std::tuple_cat(data, std::tuple{v})}; 
      }

    template <typename K> decltype(auto) get() 
    {
      return std::get<Tag2ID<K, Ks...>()>(data); 
    }
  };

struct A {};
struct B {};
struct C {};

int main()
{
  auto my_map = type_value_map<>{}.append<A>(6).append<B>(11.5).append<C>("hello"s);

  std::cout << "A => " << my_map.get<A>() << '\n';
  std::cout << "B => " << my_map.get<B>() << '\n';
  std::cout << "C => " << my_map.get<C>() << '\n';
  my_map.get<C>().append(" world!");
  std::cout << "C => " << my_map.get<C>() << '\n';
}
Last edited on
Topic archived. No new replies allowed.