Cannot return a cli array of a generic type - c++-cli

I got this function
array<ItemType>^ GetNextItems(int n) {
auto ret = gcnew Collections::Generic::List < ItemType > ;
for (int i = 0; i < n; i++) {
auto item = GetNextItem();
if (item == ItemType()) break;
ret->Add(item);
}
return ret->ToArray();
}
But the compile gives me an error: cannot convert from 'cli::array< ItemType,1 > ^' to 'cli::array< ItemType,1 > ^'
ItemType is a template parameter ie.
generic <typename ItemType>
I've been staring at this for a while, I can't detect the fault. Why won't it compile?

If ItemType is a .NET/CLR type, then you'll need the ^-hat inside the return type declaration. The ^ is still not included in the actual type declaration.
So it would be something like this:
generic <typename ItemType>
ref class Test
{
array<ItemType ^>^
GetNextItems(int n)
{
List<ItemType ^> ^ ret = gcnew List<ItemType ^>(n);
...
return ret->ToArray();
}
};
Notice the added caret inside the <ItemType ^> return type declaration, but not in the class' generic definition.

Related

recursive template function does not compile with Clang?

I have a template function which recurses over a parameter pack. In essence it is meant to map something.Get<A,B,C>() into something.Get<A>().Get<B>().Get<C>().
This can be achieved by doing (full stand-alone source below the fold)
template <typename... Pack> class Struct {
std::tuple<Pack...> mTuple;
template <typename Type> auto &GetRef_internal() {
return std::get<first_true<std::is_same<Type, Pack>::value...>::value>(
mTuple);
}
public:
template <typename Current> Current &GetRef() {
return GetRef_internal<Current>();
}
template <typename Current, typename... Next,
typename std::enable_if<sizeof...(Next) != 0>::type * = nullptr>
auto &GetRef() {
auto current = GetRef_internal<Current>();
return current.GetRef<Next...>();
}
};
where first_true returns the index of the first element which is true.
This compiles with g++, and seemingly on MSVC too using an online compiler. When compiling with clang++ I get the following error though:
test.cxx:40:31: error: expected '(' for function-style cast or type construction
return current.GetRef<Next...>();
~~~~^
test.cxx:38:9: error: cannot deduce return type 'auto &' for function with no return statements
auto &GetRef() {
^
test.cxx:48:12: note: in instantiation of function template specialization 'Struct<Struct<int, Struct<float, float> >, Struct<char>, int>::GetRef<Struct<int, Struct<float, float> >, Struct<float, float> , nullptr>' requested here
.GetRef<Struct<int, Struct<float, float>>, Struct<float, float>>();
^
2 errors generated.
What could cause this?
p.s. The actual 'production code' is more useful than the example makes it seem, but that would be too much to post here.
=========================================================================
#include <tuple>
#include <type_traits>
// Template to check if condition holds true for all members of a parameter
// pack.
template <bool... b> struct BoolArray {};
template <bool... b>
using all_true = std::is_same<BoolArray<b...>, BoolArray<(b, true)...>>;
//helper type trait
template <bool... b> struct first_true {
template <
unsigned index = 0,
typename std::enable_if<index<sizeof...(b)-1>::type * =
nullptr> static constexpr unsigned check() {
return std::get<index>(std::make_tuple(b...)) ? index : check<index + 1>();
}
template <unsigned index = 0,
typename std::enable_if<index >= sizeof...(b)-1>::type * = nullptr>
static constexpr unsigned check() {
return std::get<index>(std::make_tuple(b...)) ? index : 0;
}
static constexpr unsigned value = first_true<b...>::check();
};
//The actual problem struct
template <typename... Pack> class Struct {
std::tuple<Pack...> mTuple;
template <typename Type> auto &GetRef_internal() {
return std::get<first_true<std::is_same<Type, Pack>::value...>::value>(
mTuple);
}
public:
template <typename Current> Current &GetRef() {
return GetRef_internal<Current>();
}
template <typename Current, typename... Next,
typename std::enable_if<sizeof...(Next) != 0>::type * = nullptr>
auto &GetRef() {
auto current = GetRef_internal<Current>();
return current.GetRef<Next...>();
}
};
int main() {
// Define a random nested struct
Struct<Struct<int, Struct<float, float>>, Struct<char>, int> myStruct;
// Then retrieve one of the substructures to instantiate the template
auto substruct =
myStruct
.GetRef<Struct<int, Struct<float, float>>, Struct<float, float>>();
return 0;
}
current.GetRef<Next...> is a dependent name, so you need to specify that GetRef names a template using the template keyword:
return current.template GetRef<Next...>();
See Where and why do I have to put the "template" and "typename" keywords? for more information about dependent names.

How do i get the codec's List of ffmpeg by names?

I have this function in C
int Encoder_GetCurrentCodecType()
{
if (current_codec != NULL)
return (int) current_codec->type;
return AVMEDIA_TYPE_UNKNOWN;
}
But the function return the code of each codec type.
Like: 0,1,2,3,4,5,6,7
If i'm doing for the test in the function i type: AVMediaType::
Then i see the List of all 7 codec's types there is for example:
AVMEDIA_TYPE_AUDIO
So i want to make a function like the one with the int but string or const char* that will return me the names of the types and not the codes.
How can i do it ?
EDIT
In the C file i did:
const char* Encoder_av_get_media_type_string(enum AVMediaType media_type)
{
switch (media_type) {
case AVMEDIA_TYPE_VIDEO: return "video";
case AVMEDIA_TYPE_AUDIO: return "audio";
case AVMEDIA_TYPE_DATA: return "data";
case AVMEDIA_TYPE_SUBTITLE: return "subtitle";
case AVMEDIA_TYPE_ATTACHMENT: return "attachment";
default: return NULL;
}
}
Then in the header file that connecting between the C and C++ i did:
const char* Encoder_av_get_media_type_string(enum AVMediaType media_type);
Then in the C++ header file i did:
property List<String^> ^GetCodec
{
List<String^>^ get()
{
List<String^> ^l = gcnew List<String^>;
String ^s;
s = gcnew String(Encoder_av_get_media_type_string(avm));
l->Add(s);
return l;
}
}
Then in CSHARP i did:
for (int i = 0; i < f.GetCodec.Count; i++)
{
ss.Add(f.GetCodec[i]);
}
So maybe in C++ it shouldn't be property i thought to do something that in CSHARP when i make f.GetCodec. then it will show me a List of all the codec's types names.
Like a property like when i'm doing f.GetCodec.Add and see list of properties so f.GetCodec.(and here i will the list of all types names)
If it's impossible then just to make in CSHARP a List with all types names.
But for now i'm getting only 1 name "video" that's it.
According to this, there exists a function to do just that.
const char* av_get_media_type_string(enum AVMediaType media_type)

How do i copy to a List?

I have this code in CLI
List<Codec^> ^GetCodecs()
{
List<Codec^> ^l = gcnew List<Codec^>;
bool KeepLooping = Encoder_MoveToFirstCodec();
while (KeepLooping)
{
Codec ^codec = gcnew Codec(); // here... and that call encoder_init many times... which call register codec many times... which is a mass...
codec->Name = gcnew String(Encoder_GetCurrentCodecName());
codec->Type = Encoder_GetCurrentCodecType();
char pix_fmts[200]; // array of 200 is probably enough
int actual_pix_fmts_sz = Encoder_GetCurrentCodecPixFmts( pix_fmts , 200 );
for (int i = 0 ; i < actual_pix_fmts_sz ; i++)
{
//copy from pix_fmts to the :List
codec->SupportedPixelFormats->Add(pix_fmts[i]);
}
This is the Encoder_GetCurrentCodecPixFmts function in C:
int Encoder_GetCurrentCodecPixFmts( char *outbuf , int buf_sz )
{
int i=0;
while ( (i<buf_sz) && (codec->pix_fmts[i]!=-1) )
{
outbuf[i] = codec->pix_fmts[i];
i++;
}
return i;
}
This is a new class i did:
#pragma once
using namespace System;
using namespace System::Collections::Generic;
public ref class Codec
{
public:
String^ Name;
int ID; // this is the index
int Type; // this is the type
List<int> ^SupportedPixelFormats;
Codec(void)
{
SupportedPixelFormats = gcnew List<int>;
// do nothing in the constructor;
}
};
Which contain also the: SupportedPixelFormats
The constructor in this new class should be empty but i needed somewhere to make an instance for the List make a NEW for the List.
Now in the C++ i need to transfer from pix_fmts char array to codec->Supported
Or to copy from pix_fmts to the :List
So i did as above:
codec->SupportedPixelFormats->Add(pix_fmts[i]);
But i'm not sure if this the meaning of copy.
Is that right what i did ?
It works, it's a kind of a deep copy. What makes you think it doesn't work? Do the results turn out wrong? If they do, put a breakpoint in there and try to get what is wrong.
Instead of copying one by one perhaps you can use the Enumerable::ToList extension method.
I hope this helped you.

Make sort using delegates

I'm try to make a sort delegate in C++/CLI, but, when I try to compile I recive this erro:
>app.cpp(256): error C3374: can't take address of 'Program::AnonymousMethod1' unless creating delegate instance
>app.cpp(256): error C2664: 'void System::Collections::Generic::List<T>::Sort(System::Comparison<T> ^)' : cannot convert parameter 1 from 'System::Object ^(__clrcall *)(Program::teste1,Program::teste1)' to 'System::Comparison<T> ^'
> with
> [
> T=Program::teste1 ^
> ]
> No user-defined-conversion operator available, or
> There is no context in which this conversion is possible
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
here is the code sample of the error:
using namespace System;
using namespace System::Collections::Generic;
private ref class Program
{
private:
enum class tokens
{
teste,
lala,
blabla,
};
ref struct teste1
{
int linha;
tokens tk;
};
private:
static Object ^AnonymousMethod1(teste1 p1, teste1 p2)
{
return p1.tk.CompareTo(p2.tk);
}
public:
Program()
{
bool jump = false;
List<teste1^>^ lstTest = gcnew List<teste1^>();
Random ^rnd = gcnew Random();
for (int i = 0; i < 20; i++)
{
teste1 ^tst = gcnew teste1();
switch (rnd->Next(1,4))
{
case 1:
tst->tk = tokens::teste;
break;
case 2:
tst->tk = tokens::lala;
break;
case 3:
tst->tk = tokens::blabla;
break;
}
lstTest->Add(tst);
}
for each (teste1^ content in lstTest)
{
Console::WriteLine(content->tk.ToString());
}
lstTest->Sort(AnonymousMethod1);
Console::WriteLine("==============================================================");
for each (teste1^ content in lstTest)
{
Console::WriteLine(content->tk.ToString());
}
}
};
int main(array<String^> ^args)
{
Program^ prg = gcnew Program();
return 0;
}
I just whant to sort the list with the token 'lala' first, how I can make this, and, How I can solve this ???
Your List is of type List<test1^> (notice the ^ hat). So the Comparison<T> delegate you want is Comparison<teste1^>. Thus you'll want to change your AnonymousMethod1 as follows:
static int AnonymousMethod1(teste1 ^ p1, teste1 ^ p2)
{
return p1->tk.CompareTo(p2->tk);
}
And in C++/CLI you need to explicitly create your delegate:
Comparison<teste1 ^> ^ comparisonDelegate = gcnew Comparison<teste1 ^>(&AnonymousMethod1);
lstTest->Sort(comparisonDelegate);

char and initializer lists

I'd like to pass some numeric byte values via an initializer list a variadic template into an array. Is that possible?
template < int N > struct a {
char s[N];
template < typename ... A >
a (A ... _a) : s {_a...} {}
};
int main () {
// g++-4.5: error: narrowing conversion of »_a#0« from »int« to »char« inside { }
a < 3 > x { 1, 2, 3 };
}
What I can think of is
to use octal representation, '\001' etc., or
to cast every single value.
But both is not satisfying.
You don't need any complicated code
template < int N > struct a {
char s[N];
template < typename ... A >
a (A ... _a) : s {static_cast<char>(_a)...} {}
};
NOTE: All of this is unnecessary unless you have added functionality to the class so it's no longer an aggregate. (For example, other constructors, private members, a base class, etc.) The immediate way to fix the code in the question is simply to remove the constructor. So, let's assume there's something more to it.
I've seen some people trying to do things like this. It seems ugly, dealing with conversion semantics and trying to artificially re-create the functionality of a usual function call.
Here is a strategy to create an array class that simply has the right constructor in the first place.
Template aliasing would put the icing on the cake by hiding the ::type ugliness, but it's not in GCC yet.
template< typename ... NT >
struct var_ctor_array {
enum { size_e = 0 }; // only used for zero size case
};
template< typename T, typename ... NT >
struct var_ctor_array< T, NT ... > {
enum { size_e = 1 + sizeof...( NT ) };
T st[ size_e ];
var_ctor_array( T elem0, NT ... elemN )
: st { elem0, elemN ... } {}
};
template< typename T, size_t N, typename ... NT >
struct gen_var_ctor_array {
typedef typename gen_var_ctor_array< T, N-1, T, NT ... >::type type;
};
template< typename T, typename ... NT >
struct gen_var_ctor_array< T, 0, NT ... > {
typedef var_ctor_array< NT ... > type;
};
int main() { // usage
gen_var_ctor_array< char, 5 >::type five( 1, 2, 3, 4, 5 );
}
You're not actually using initializer lists. The constructor receives a variadic template and you initialize x with uniform initialization.
The only problem is I don't know of an elegant way of initializing an array with an initializer_list, AFAIK std::array should have a constructor that accepts initializer_list but it doesn't seem to be supported by g++ yet.
#include <utility>
template < int N > struct a {
char s[N];
a (std::initializer_list<char> list) {
if (N != list.size())
throw "list wrong size";
int i = 0;
const char* p = list.begin();
while(p != list.end())
s[i++] = *p++;
}
};