2017-12-16 18 views
1

Ich versuche eine Klasse zu schreiben, um einen Tensor Tensor darzustellen und möchte die Syntax tensor(i, j) für einen 2-dimensionalen Tensor, tensor (i, j, k) für einen 3-dimensionalen Tensor und so weiter zur Verfügung stellen.Variadic Funktion

Was ich wissen möchte, ist, wenn es ein C++ Typ sichere Art und Weise solche Tensor:operator()(int, int, ...) zu erklären, dass eine beliebige Anzahl von int Argumente akzeptiert (neben der C-Stil mit den Makros va_start va_end) und wie in der Funktion die Argumente zu verwenden.

Danke für Ihre Zeit.

+0

Was variadische Template-Parameter-Pack machen sein? – user0042

+0

Sie können variante C++ - Vorlagen verwenden und das Argument als einen bestimmten Typ (oder konvertierbar in einen bestimmten Typ) definieren. Die Verwendung der resultierenden Parameterpakete ist jedoch ein wenig mühsam. –

+0

Ist die tensors-Dimension eine Laufzeiteigenschaft oder eine Kompilierzeiteigenschaft? – StoryTeller

Antwort

2

Nun, Sie könnten immer ein gewöhnliches Parameterpaket verwenden; aber zwingen, eine Kompilation Ausfall, wenn alle Parameter sind int s:

#include <utility> 
#include <type_traits> 


class foo { 

public: 

    template<typename ...Args, 
     typename=std::void_t<std::enable_if_t 
         <std::is_same_v<Args, int>>...>> 
    void operator()(Args ...args) 
    { 
    } 
}; 

void bar() 
{ 
    foo bar; 

    bar(4, 2); 
} 

Das kompilieren, aber nicht so:

bar(4, "foo"); 

oder

bar(4, 2.3); 

Beachten Sie, dass dies nicht kompiliert entweder:

unsigned baz=2; 

bar(4, baz); 

Wenn Sie nicht signierte Werte akzeptieren müssen, tweeten Sie die Vorlage entsprechend.

Beachten Sie, dass die Vorlage keine Weiterleitungsreferenz verwenden muss, da die einzigen zulässigen Parameter einfach int s sind. Innerhalb der Template-Funktion haben Sie jetzt ein Garden-Variety-Parameterpaket, das Sie genauso verwenden würden wie jedes andere Parameter-Pack.

+1

Auch op könnte 'std :: is_convertible' oder etwas ähnliches anstelle von' std :: is_same' verwenden. – HolyBlackCat

1

Um auch unsigned int und andere Arten zu annehmen, die int umwandelbar sind, und wenn Sie eine Obergrenze annehmen kann (63, im folgenden Beispiel) auf die Anzahl der Integer-Argument, schlage ich vor, an example from W.F. zu folgen.

So können Sie entwickeln eine typer

template <typename T, std::size_t> 
using typer = T; 

und eine rekursive struct proOp

template <typename T, std::size_t N = 64U, 
      typename = std::make_index_sequence<N>> 
struct proOp; 

template <typename T, std::size_t N, std::size_t... Is> 
struct proOp<T, N, std::index_sequence<Is...>> : public proOp<T, N-1U> 
{ 
    using proOp<T, N-1U>::operator(); 

    void operator() (typer<T, Is>... ts) 
    { } 
}; 

template <typename T> 
struct proOp<T, 0U, std::index_sequence<>> 
{ 
    void operator()() 
    { } 
}; 

von proOp<int> Vererben, Tensor werden

struct Tensor : public proOp<int> 
{ 
    using proOp<int>::operator(); 
}; 

Das Folgende ist ein voll funktionierendes Beispiel

#include <utility> 

template <typename T, std::size_t> 
using typer = T; 

template <typename T, std::size_t N = 64U, 
      typename = std::make_index_sequence<N>> 
struct proOp; 

template <typename T, std::size_t N, std::size_t... Is> 
struct proOp<T, N, std::index_sequence<Is...>> : public proOp<T, N-1U> 
{ 
    using proOp<T, N-1U>::operator(); 

    void operator() (typer<T, Is>... ts) 
    { } 
}; 

template <typename T> 
struct proOp<T, 0U, std::index_sequence<>> 
{ 
    void operator()() 
    { } 
}; 

struct Tensor : public proOp<int> 
{ 
    using proOp<int>::operator(); 
}; 

int main() 
{ 
    Tensor t; 

    t(1, 2, 3); 
    t(1, 2, 3, 4U); // accept also unsigned 
    //t(1, "two"); // error 
} 
1

könnte eine andere Art und Weise operator() rekursive und verwenden Sie das erste Argument in jeder Rekursion

// recursive case 
    template <typename ... Ts> 
    void operator() (int i0, Ts ... is) 
    { 
     // do something with i0 
     this->operator()(is...); // recursion 
    } 

    void operator()() 
    { } 

Das Folgende ist ein voll funktionierendes Beispiel

struct Tensor 
{ 
    // recursive case 
    template <typename ... Ts> 
    void operator() (int i0, Ts ... is) 
    { 
     // do something with i0 
     this->operator()(is...); // recursion 
    } 

    void operator()() 
    { } 
}; 

int main() 
{ 
    Tensor t; 

    t(1, 2, 3); 
    t(1, 2, 3, 4U); // accept also unsigned 
    //t(1, "two"); // error 
} 
Verwandte Themen