[C++] T -> const T afhankelijk van constness van U

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Stel, ik heb een template class met type T, bijvoorbeeld = char*. Nu wil ik een memberfunctie schrijven met argument type const void* als T const is en type void* zoniet. Hoe is dit te doen?

C++:
1
2
3
4
5
6
7
8
9
template <class T>
class basic_data_ref
{
public:
    basic_data_ref(const void* begin, const void* end)
    {
        assign(begin, end);
    }
}

Acties:
  • 0 Henk 'm!

  • cpt.spiff
  • Registratie: Augustus 2009
  • Laatst online: 20-02 14:29
Het makkelijkst is dat met boost. Zonder boost is het iets meer puzzelen, maar kan het (obviously) ook.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_const.hpp>
#include <boost/type_traits/add_const.hpp>

/// template meta function that will return a const-qualified version of BaseType if
/// PossibleConstType is const and returns BaseType itself if PossibleConstType isn't.
template<typename base_type, typename possible_const_type>
struct const_if_second_is_const
{
    typedef typename boost::mpl::if_<
        typename boost::is_const< possible_const_type>::type,
        typename boost::add_const<base_type>::type,
        base_type
        >::type type;
};


template <typename T>
struct test
{
    typedef typename const_if_second_is_const<void, T>::type *pointer_type;

    test( pointer_type begin, pointer_type end){};
};

Acties:
  • 0 Henk 'm!

  • cpt.spiff
  • Registratie: Augustus 2009
  • Laatst online: 20-02 14:29
ach, het is zonder boost eigenlijk ook wel zo compact:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template< typename T>
struct appropriate_pointer_type
{
    typedef void *type;
};

template<typename T>
struct appropriate_pointer_type<const T>
{
    typedef const void *type;
};

template <typename T>
struct test
{
    typedef typename appropriate_pointer_type<T>::type pointer_type;

    static void test_func( pointer_type begin, pointer_type end){};
};

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Of je gebruikt gewoon TR1, waar elke compiler tegenwoordig wel mee shipt.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <type_traits>
namespace std { using namespace tr1; } // mocht TR1 nog niet in std zitten.

template <class T> 
class basic_data_ref 
{ 
public: 
    typedef typename std::conditional<std::is_const<T>::value, const void*, void*>::type void_pointer;

    basic_data_ref(void_pointer begin, void_pointer end) 
    { 
        assign(begin, end); 
    } 
};


.edit: oh wacht, dit klopt niet helemaal, maar je beschrijving is ook een beetje krom:
Stel, ik heb een template class met type T, bijvoorbeeld = char*. Nu wil ik een memberfunctie schrijven met argument type const void* als T const is en type void* zoniet
als T een const char* is, dan is T niet const - de char waarnaartoe verwezen wordt is const.

Waarschijnlijk wil je 'm dus eerst even door std::remove_pointer<> heen halen alvorens je test op std::is_const<>

[ Voor 41% gewijzigd door .oisyn op 23-09-2011 17:32 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Hmm, handig!
C++:
1
2
3
4
5
6
7
8
9
template<class T>
void f(T&)
{
}

int main()
{
  f(7);
}

invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’
in passing argument 1 of ‘void f(T&) [with T = int]’

Waarom gebruikt de compiler hier T = int in plaats van T = const int? Nu kan ik zowel een const als mutable overload schrijven.

[ Voor 4% gewijzigd door Olaf van der Spek op 25-09-2011 01:11 ]


  • xos
  • Registratie: Januari 2002
  • Laatst online: 12-09 12:41

xos

Waarschijn zal .oisyn mij wel verbeteren maar toch een poging. Volgens mij haal je const en rvalues door elkaar. De string constructor zal een string terug geven en geen const string. Oftewel, de compiler zal void f<std::string> instantieren. Maar omdat het ook een temporary is en dus een rvalue had er f<const std::string> geinstatieerd moeten worden. En daarom geeft de compiler deze melding. Je kunt het oplossen door:

C++:
1
2
3
4
5
6
7
8
9
template<class T>
void f(T&)
{
}

int main()
{
        f<const std::string>(std::string("Olaf"));
}


Overigens weet ik niet waarom de compiler en jij het in je reactie over een int hebt en je code een string gebruikt. Copy paste issue?

Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
xos schreef op zaterdag 24 september 2011 @ 21:40:
Overigens weet ik niet waarom de compiler en jij het in je reactie over een int hebt en je code een string gebruikt. Copy paste issue?
Ja, ik had de code versimpeld maar was vergeten de nieuwe code te posten. Bij deze.
Dat het type in principe (nu) int is begrijp ik, maar dat is niet te binden. Dus had ik verwacht dat de compiler T = const int zou gebruiken, maar blijkbaar is dat niet toegestaan.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Een rvalue bind nooit naar een non-const reference in een template, en het type zal altijd deduceren naar T, en niet naar een const T (want een rvalue is geen const T).
Nu kan ik zowel een const als mutable overload schrijven.
Hier bedoel je waarschijnlijk volatile ipv mutual ;), maar nee, de enige die je mist zijn rvalues. Als je het hebt over een lvalue dan zal T wel deduceren naar c/v int als nodig:
C++:
1
2
3
4
5
int main()
{
    const int i = 4;
    F(i);  // T = const int
}


Als je alles in een wilt kun je beter gebruik maken van rvalue references
C++:
1
2
3
4
5
6
7
8
9
10
template<class T> void F(T&& t) { }

int main()
{
    int i = 3;
    const int ci = 4;
    F(i);  // T = int&
    F(ci); // T = const int&
    F(5);  // T = int
}

[ Voor 45% gewijzigd door .oisyn op 25-09-2011 13:49 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
.oisyn schreef op zondag 25 september 2011 @ 13:33:
Een rvalue bind nooit naar een non-const reference in een template, en het type zal altijd deduceren naar T, en niet naar een const T (want een rvalue is geen const T).
Maar T werkt niet, dus had ik gehoopt dat const T gekozen zou worden.
Hier bedoel je waarschijnlijk volatile ipv mutual ;), maar nee, de enige die je mist zijn rvalues.
Nee, ik bedoelde non-const.
Als je alles in een wilt kun je beter gebruik maken van rvalue references
Helaas is C++11 nog geen optie in dit geval.
.oisyn schreef op vrijdag 23 september 2011 @ 17:28:
Of je gebruikt gewoon TR1, waar elke compiler tegenwoordig wel mee shipt.
<type_traits> is C++11 toch? <tr1/type_traits> is TR1, volgens G++. Maar die heeft VC natuurlijk weer niet.
En zit is_conditional wel in TR1? Volgens Boost niet: http://www.boost.org/doc/...boost/tr1/type_traits.hpp

[ Voor 24% gewijzigd door Olaf van der Spek op 25-09-2011 16:17 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

<tr1/type_traits> is TR1, volgens G++
Volgens G++ wel ja.
It is recommended either that additional declarations in standard headers be protected with a macro that is not defined by default, or else that all extended headers, including both new headers and parallel versions of standard headers with nonstandard declarations, be placed in a separate directory that is not part of the default search path.
't Kon dus net zo goed <henk/type_traits> zijn. Best wel suf eigenlijk.
En zit is_conditional wel in TR1
Je bedoelt conditional, die lijkt er idd niet in te zitten... Maar goed:

C++:
1
2
3
4
5
template<bool V, class T> struct enable_if { };
template<class T> struct enable_if<true, T> { typedef T type; };

template<bool V, class T, class F> struct conditional { typedef T type; };
template<class T, class F> struct conditional<false, T, F> { typedef F type };

[ Voor 95% gewijzigd door .oisyn op 25-09-2011 16:44 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Uit m'n "Tough Interview Questions" collectie (is overigens wel productiecode)
C++:
1
2
3
4
5
6
7
8
9
10
    template <typename SRC, typename DST>
    struct CopyConst {
        typedef DST  value_type;
        typedef DST* pointer; 
    };
    template <typename SRC, typename DST>
    struct CopyConst<SRC const, DST> {
        typedef DST const  value_type;
        typedef DST const* pointer; 
    };

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein

Pagina: 1