2015-09-21 20 views
5

Uwaga: przykład podany w tym pytaniu nie jest kodem produkcyjnym i nie ma żadnego sensu. Jest po to, aby zilustrować mój problem.Typ parametru funkcji przy użyciu dekltype

ja testował możliwości decltype, zwłaszcza gdy jest ona wykorzystywana do wywnioskować typy parametrów funkcji, i wpadł na pewien problem:

Załóżmy, że były dwie klasy strukturyzowanych tak:

struct ClassInt 
{ 
    // Note: no default ctor 
    ClassInt(int value) 
     : m_Value(value) 
    {} 

    int m_Value; 
}; 

struct ClassDouble 
{ 
    // Note: no default ctor 
    ClassDouble(double value) 
     : m_Value(value) 
    {} 

    double m_Value; 
}; 

Teraz napisałem funkcję, która (w jakiś sposób) pobiera wystąpienie parametru typu (który powinien być jednym z powyższych) za pomocą ciągu znaków i przypisuje daną wartość do jego elementu m_Value:

template< typename Ty > 
Ty* get_fake_ptr() { return nullptr; } 


// Retrieve pointer to Ty object by name and assign its value member. 
// The problem is that we don't actually have an instance of Ty at the point 
// where we want to define the type of the parameter "value". 
template< typename Ty > 
void assign(std::string name, decltype(get_fake_ptr<Ty>()->m_Value) value) 
{ 
    // Somehow get pointer to a Ty object by name 
    Ty* obj = ????; 

    // Assign 
    obj->m_Value = value; 
} 

Teraz typ parametru value zależy od parametru typu, ponieważ używane klasy różnią się typem elementu m_Value. Jak widać, rozwiązałem go, używając decltype. Teraz normalnie użyłbyś decltype na parametr, tak:

template<typename Ty> 
void assign(Ty& obj, decltype(obj.m_Value) value); 

Ale to oczywiście nie jest tutaj możliwe, ponieważ rzeczywista instancja zostanie pobrana w ciele funkcji i nie jest zatem dostępna w miejscu, gdzie argumenty funkcji są zadeklarowane.

Zhackowałem to razem, używając funkcji szablonu get_fake_ptr, która właśnie zwraca nullptr odpowiedniego typu, więc mam "pseudoinstrukcję", którą kompilator może użyć do określenia typu elementu. I to działa:

working

Teraz, jak już mówiłem, to wydaje mi się naprawdę hacky. A więc:

Czy istnieje lepszy sposób na rozwiązanie tego problemu?

Dziękujemy!

+2

Możesz użyć 'decltype (std :: declval () .m_Value), aby wydedukować typ elementu m_Value T zamiast używać funkcji' get_fake_ptr() '. W końcu osiągają podobne cele. –

+1

Nawiasem mówiąc, twoja funkcja 'get_fake_ptr()' nie musi być zdefiniowana. Możesz łatwo zostawić go jako 'szablon T * get_fake_ptr();' i nadal możesz go używać wewnątrz 'decltype'. –

+1

Co jest nie tak z 'decltype (Ty :: m_value)'? – Casey

Odpowiedz

3

Można użyć decltype(std::declval<T>().m_Value) wydedukować rodzaj T „s m_Value członka zamiast korzystania z funkcji get_fake_ptr(). W końcu osiągają podobne cele.

Nawiasem mówiąc, funkcja get_fake_ptr() nie musi być zdefiniowana. Możesz łatwo zostawić go jako template <typename T> T* get_fake_ptr(); i nadal możesz go używać wewnątrz decltype.

3

Nie widzę niczego złego w tym podejściu.

Jeśli chodzi o meta-programowanie szablonowe, tego rodzaju "hacki" są parami dla kursu.

Mogę zaproponować nieco inny wzór. Coś w tym stylu:

struct ClassInt 
{ 
    // Note: no default ctor 
    ClassInt(int value) 
     : m_Value(value) 
    {} 

    typedef int m_value_t; 

    m_value_t m_Value; 
}; 

struct ClassDouble 
{ 
    // Note: no default ctor 
    ClassDouble(double value) 
     : m_Value(value) 
    {} 

    typedef double m_value_t; 

    m_value_t m_Value; 
}; 

// ... 
template< typename Ty > 
void assign(std::string name, typename Ty::value_t value) 
{ 
    // Somehow get pointer to a Ty object by name 
    Ty* obj = ????; 

    // Assign 
    obj->m_Value = value; 
} 
2

Kolejną alternatywą jest dodanie kolejnego parametru szablonu i pozwolenie, aby uchwyt przydzielił pasujące typy i konwersje. Dowolne typy wartości, które nie mogą zostać przekształcone, wygenerują błąd kompilacji.

template<typename Ty, typename VALUE_TYPE> 
void assign(std::string name, VALUE_TYPE value) { 
    Ty* obj = ??? 
    obj->m_Value = value; 
} 
Powiązane problemy