Reputation: 33
I am a bit in stuck and need a help from C++ template guru. There is a template struct:
template<typename T, typename ID>
struct TypeMapping
{
T Type;
char* Name;
ID Id;
};
and a few template functions like this:
template<typename T, typename ID>
bool TryGetTypeByNameImp(const TypeMapping<T, ID> map[], size_t mapSize,
const char* name, T& type)
{
for (size_t i = 0; i < mapSize; i++)
{
if (strcmp(map[i].Name, name) == 0)
{
type = map[i].Type;
return true;
}
}
return false;
}
Map (the first parameter) is defined as (there are a few similar maps)
namespace audio
{
const TypeMapping<Type, AMF_CODEC_ID> Map[] =
{
{AAC, "aac", AMF_CODEC_AAC},
{MP3, "mp3", AMF_CODEC_MP3},
{PCM, "pcm", AMF_CODEC_PCM_MULAW}
};
const size_t MapSize = sizeof(Map)/sizeof(Map[0]);
}
Map is passed to a function as an argument and I am looking for how to pass it as template parameter so I can use functions like in this sample:
audio::Type type;
bool r = TryGetTypeByNameImp<audio::Map>("aac", type);
The only solution I found it is to define a struct which holds static Map and MapSize and use the struct as template parameter but I do not like this solution and I am looking for another one. Does anybody know how to do this?
Upvotes: 3
Views: 593
Reputation: 545588
bool r = TryGetTypeByNameImp<audio::Map>("aac", type);
This is trying to use audio::Map
as a type – but it isn’t, it’s a variable. Just pass it to the function as a normal argument:
bool r = TryGetTypeByNameImp(audio::Map, "aac", type);
That said, I have three remarks about your code:
x[]
) does in reality declare it as a pointer. Your code uses this correctly, but using the array syntax is misleading. Use a pointer instead.char*
is illegal in C++11, and deprecated in C++03 (since you are pointing to string literals). Use char const*
. Furthermore, I’d suggest using a std::string
argument in the function, and using the comparison operator ==
instead of strcmp
.You are using an out-parameter, type
. I abhor this technique. If you want to return a value, use the return type. Since you also return a success value, use a pair
as the return type, unless there’s a very compelling reason not to:
template<typename T, typename ID>
std::pair<bool, T> TryGetTypeByNameImp(
const TypeMapping<T, ID> map[], size_t mapSize,
const char* name)
{
for (size_t i = 0; i < mapSize; i++)
if (strcmp(map[i].Name, name) == 0)
return std::make_pair(true, map[i].Type);
return std::make_pair(false, T());
}
Ah, and I’d also consider using a std::vector
or std::array
here instead of a C array. Then you don’t need to manually shlep the array size around through all the functions which use the array.
Upvotes: 2
Reputation: 157354
You can certainly use the array itself (well, a pointer to it) as a template parameter:
#include <iostream>
template<typename T> struct S { T t; };
S<int> s[] = { { 21 }, { 22 } };
template<typename T, size_t n, S<T> (*m)[n]> void f() { std::cout << (*m)[n - 1].t; }
int main() {
f<int, 2, &s>();
}
The problem here is that you can't use template argument deduction on the length of the array nor on its type, so both must be supplied as template parameters in addition to the array itself. I really think that passing in a struct or, say a vector would be the better solution, as you've no doubt already explored:
#include <vector>
#include <iostream>
template<typename T> struct S { T t; };
std::vector<S<int>> s{ { 21 }, { 22 } };
template<typename T, std::vector<S<T>> *v> void f() { std::cout << v->back().t; }
int main() {
f<int, &s>();
}
Upvotes: 1