Huh? » C++-Templates http://phresnel.org/blog D'Oh! (feel free to leave me a mail at "phresnel.gmail@com , swap @ with . for proper mail) Fri, 12 Feb 2010 09:17:43 +0000 en hourly 1 http://wordpress.org/?v=3.1.2 Yo Mama is C++0x! http://phresnel.org/blog/2009/09/yo-mama-is-cpp0x/ http://phresnel.org/blog/2009/09/yo-mama-is-cpp0x/#comments Fri, 25 Sep 2009 14:58:32 +0000 phresnel http://phresnel.org/blog/?p=117 Continue reading ]]> This is a side product of some evil plan to emit hundreds of fixed codepaths at compile time, for the sake of better performance for some simple ifs-fractals-renderer i hack at the moment (itself being an exercise in OpenMP, C++0x (as far as g++4.4 goes), Optimization, and patience of course).

So, what follows is a function that reminds of .net’s WriteLine()-family, which some say to be a typesafe variant of printf() (yes, the one dreaded for its ellipsis parameter, possibly opening the door to all kinds of vulnerabilities), and hence better. Of course there are iostreams in C++, but they have the disadvantage that you cannot flip arguments around during runtime, making them a non-option for internationalization purposes. You could also overload operators so as to produce typesafe variants of printf(). Anyways, I was snoopy about variadic templates in C++0x. And as it turned out, variadic templates are a bless!

#include <sstream>
#include <string>
#include <iostream>
#include <stdexcept>
 
// lambdas not yet
template <typename T> std::string to_string (T val) {
        std::stringstream ss;
        ss << val;
        return ss.str();
}
 
template <typename ...ARGS>
void write (std::string const & fmt, ARGS... args) {
        const std::string argss[] = {to_string (args)...}; // <- indeed
        enum {argss_len = sizeof (argss) / sizeof(argss[0])};
 
        // no range based for loops yet ("for (auto it : fmt)")
        for (auto it = fmt.begin(); it != fmt.end(); ++it) {
                if (*it == '{') {
                        auto const left = ++it;
                        for (; it != fmt.end(); ++it) {
                                // closing brace: fine
                                if (*it == '}')
                                        break;
                                // check if numeric. if not, throw.
                                switch (*it) {
                                default:
                                        throw std::invalid_argument (
                                        "syntax error in format string, "
                                        "only numeric digits allowed between "
                                        "braces"
                                        );
                                case '0':case '1':case '2':case '3':case '4':
                                case '5':case '6':case '7':case '8':case '9':;
                                };
                        }
                        if (*it != '}') {
                                throw std::invalid_argument (
                                        "syntax error in format string, "
                                        "missing closing brace"
                                );
                        }
                        auto const right = it;
 
                        if (left == right) {
                                throw std::invalid_argument (
                                        "syntax error in format string, "
                                        "no index given inside braces"
                                );
                        }
 
                        std::stringstream ss;
                        ss << std::string(left,right);
                        size_t index;
                        ss >> index;
                        if (index >= argss_len) {
                                throw std::invalid_argument (
                                        "syntax error in format string, "
                                        "index too big"
                                );
                        }
                        std::cout << argss[index];
                } else {
                        std::cout << *it;
                }
        }
}
 
void write (std::string const & str) {
        std::cout << str;
}
 
template <typename ...ARGS> void writeln (std::string const & fmt, ARGS... args) {
        write (fmt, args...);
        std::cout << '\n';
}
 
void writeln (std::string const & str) {
        std::cout << str << '\n';
}

You can invoke this function like this (no ofuscation through operator overloading, full typesafety):

int main() {
        writeln ("Test: [{0},{1}]", 42, 3.14159);
        writeln ("Test: {1}/{0}!{0}?{0}!!", 43, "hello wurldz");
        writeln ("Test: ");
        return 0;
}

C++0x will also allow for user defined literals, allowing you to process strings (as in “strings”) at compile time, but it has not been scheduled for implementation in GCC as of time of writing.

I initially did some yacking about emitting hundreds of fixed codepaths for performance reasons. Have a look at the following example for a glimpse about how I will do it:

enum class Xtype {
        add,
        sub,
        yo,
        mama,
        end_
};
template <Xtype ...args> struct test;
template <> struct test <> {
        static void exec () {
                std::cout << "-term-\n";
        }
};
template <Xtype ...others> struct test<Xtype::add, others...> {
        static void exec () {
                std::cout << "add\n";
                test<others...>::exec();
        }
};
template <Xtype ...others> struct test<Xtype::sub, others...> {
        static void exec () {
                std::cout << "sub\n";
                test<others...>::exec();
        }
};
template <Xtype ...others> struct test<Xtype::yo, others...> {
        static void exec () {
                std::cout << "yo\n";
                test<others...>::exec();
        }
};
template <Xtype ...others> struct test<Xtype::mama, others...> {
        static void exec () {
                std::cout << "mama\n";
                test<others...>::exec();
        }
};
int main() {
        test<
                Xtype::add,
                Xtype::add,
                Xtype::sub,
                Xtype::sub,
                Xtype::add,
                Xtype::add,
                Xtype::sub,
                Xtype::yo,
                Xtype::mama,
                Xtype::yo,
                Xtype::mama,
                Xtype::yo,
                Xtype::yo
        >::exec();
        return 0;
}

Output:

add
add
sub
sub
add
add
sub
yo
mama
yo
mama
yo
yo
-term-

No more need for clumsy nesting or for std::tuple (surely std::tuple itself largely profits from variadic templates; for the curious: the boost implementation of tuple is essentially a template with a plethora of parameters (http://www.boost.org/doc/libs/1_40_0/libs/tuple/doc/tuple_users_guide.html).

Btw, the status of implementation of C++0x in GCC is at http://gcc.gnu.org/projects/cxx0x.html, the implementation status of the updated standard library is at http://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.200x.

If you are snoopy yourself, invoke g++ with -std=c++0x (all lowercase!).

]]>
http://phresnel.org/blog/2009/09/yo-mama-is-cpp0x/feed/ 0
This (->) is not only a matter of style. http://phresnel.org/blog/2009/04/this-is-not-only-a-matter-of-style/ http://phresnel.org/blog/2009/04/this-is-not-only-a-matter-of-style/#comments Wed, 01 Apr 2009 17:10:35 +0000 phresnel http://phresnel.org/blog/?p=99 Continue reading ]]>

Quote:

Original post by Saruman

Quote:

Original post by caldiar
What I’m doing wouldn’t happen to be using that hidden this pointer I keep reading about would it?


That is exactly what you are doing by using this->function2() although you don’t need it at all. In C++ this-> is implied when calling member functions.

There is really zero reason you would ever do that in front of a function, but some people use this-> before member variables in order to avoid code warts. (i.e. instead of naming member variables something like: m_myVariable they will use this->myVariable)

Using this-> is actually a good practice if you write templates.

Consider the following example:

#include <iostream>
 
void vfun() {
        std::cout << "::vfun()n";
}
 
template <typename T> struct X {
        virtual void vfun() const { std::cout << "X::vfun()n"; }
};
 
template <typename T> struct Y : public X<T> {
        void fun () { vfun(); }
};
 
template <typename T> struct Z : Y<T> {
        virtual void vfun() const { std::cout << "Z::vfun()n"; }
};
 
int main () {
        Z<int> z;
        z.fun();
        std::cout << std::flush;
}

Remember that templates are parsed two times: One time the template definition itself is parsed, so errors in the template itself can be found, and another time upon instantiation, so errors resulting from specialisations can be found (early C++ compilers implemented templates more like ordinary #define macros; but we know how hard finding bugs can be that way). Also, only during the second phase, “templated” base classes can be looked up.

At first, a global function vfun() is defined. Nothing special. Then, a class template X<T> is defined. X defines a virtual function “vfun()”.

Another class template Y<T> is then defined, which derives from X<Y>, but it does not re-implement the virtual function X::vfun(). No problem yet. Y<T> also defines a member function, named fun(), which itself calls vfun(). (There’s a third class template, struct Z<T>, but we ignore it for now.)

Here’s struct Y again:

template <typename T> struct Y : public X<T> {
        void fun () { vfun(); }
};

The problem now is, that the call to vfun() is unqualified (no ::vfun() or Y<X>::vfun(), just the pure function name). Furthermore, the arguments you pass to it don’t depend on a template parameter (in this example, we are actually passing no argument at all). Thus, the call doesn’t qualify for Argument Dependent Lookup (ADL).

You would now think, “why does the compiler not just lookup the baseclass?”. The answer lies in possible side effects due to explicit or partial specialisations (which can legally occur everywhere in the code), which basically means that e.g. a template specialisation X<bool> could be defined in a completely different way than X<float>, e.g. X<bool> could define “enum { pipapo = 0 };”, whereas X<float> could  define pipapo as “typedef X pipapo;”.

So, what remains is to use ordinary lookup of non-dependent names only, which is approximately the type of lookup you would have in a C program,  because during the second parse, only ADL and lookup of dependent names occur.

Explicitly qualifying the call to vfun()

If there wouldn’t be a global vfun() (just try yourself), standards compliant compilation should trigger an error about a call to an undeclared function. But with the global vfun(), the compiler happily finds it unambiguously using ordinary lookup. Thus, instead of calling the base classes’ virtual member function “vfun()”, Y<T>::fun() will call the global one.

A solution to this is to qualify the name:

template <typename T> struct Y : public X<T> {
        void fun () { X<T>::vfun(); }
};

Now, the correct function gets called, because we made the call dependent upon a template parameter, so that name-lookup is delayed until the second phase.

We just inhibited the virtual function call mechanism

But still, we have a problem if another class derives from Y<> and overrides vfun(). Here, our previously ignored struct Z<T> comes into play:

template <typename T> struct Z : Y<T> {
        virtual void vfun() const { std::cout << "Z::vfun()n"; }
};

Note that Z<T> also derives fun() from Y<T>, our previous “problem” function. But in “Y<T>::fun()”, we qualified the call to vfun() with X<T>::vfun(), which unfortunately means that we inhibited virtual function calling rules, and have fallen back to a non-virtual call. So, if we now call Z<T>::vfun() through a pointer or reference to struct X, we really call X<T>::vfun(), and not the overriden version in Z<T>.

While this might have been intentional, what if you really want to call the most derived vfun() inside fun(), instead of calling the least derived version? How can me make the virtual call dependent on a template parameter so that lookup can be delayed to the second phase of template parsing?, without interfering with any derivation rules?

this-> is the solution

Consider that the this-> pointer itself is a dependent name inside a class template, as its type is only completely determined once the template is intantiated (-> lookup delayed to second phase). So the simple solution to our not too obvious problem is, when writing a template, to use this-> whenever possible (*).

Here is our modified example:

template <typename T> struct Y : public X<T> {
        void fun () { this->vfun(); }
};

So, actually, using “this->” whenever possible is good style when writing templates. It is not needed in case of an explicit specialisation (**), because an explicit specialisation is basically the same as an ordinary non-template class or function, where each entity can be looked up upon the first parse (in an explicit specialisation, this-> is non-dependent, so we could not even direct the lookup until a second phase as all non-dependent names are only looked up in the first phase; despite that no second phase exists for explicit specialisations (***)).

Footnotes

(*) Except, of course, in the case where we are really interested in a very specific entity, like the global vfun() in our example.

(**) If you would write the following specialisation, this-> can be ommitted, as the compiler can fully instantiate X<int> and Y<int>, and thus find the virtual member function vfun().

template <> struct Y<int> : X<int> {
        void fun () { vfun(); } // Will call the virtual
                                // function, not the global one.
};

(***) Though a partial specialisation still contains dependent names, and all of the said still applies.

Appendix

In an answer to Hummm below, I’ve mashed up the following snippet for you to play with. It has some explanations; just don’t forget about two-phase lookup:

#include <iostream>
void vfun() {
        std::cout << "::vfun()\n";
}
 
template <typename T> struct X {
        virtual void vfun() const { std::cout << "X::vfun()\n"; }
};
 
template <typename T> struct Y : public X<T> {
        // During compilation, only the global vfun()
        // is visible, so this will call ::vfun().
        void fun0 () { vfun(); }
 
        // This will explitily call X::vfun()
        // and inhibit virtual function dispatch.
        void fun1 () { X<T>::vfun(); }
 
        // Qualifying the call with this makes the call
        // to vfun() "dependent", as the type of 'this'
        // depends on X<T>, which is not yet known.
        // Thus, the compiler will postpone
        // name-lookup until Phase 2 of template parsing.
        void fun2 () { this->vfun(); }
};
 
template <typename T> struct Z : Y<T> {
       virtual void vfun() const { std::cout << "Z::vfun()\n"; }
};
 
int main () {
        Z<int> z;
        z.fun0();
        z.fun1();
        z.fun2();
        std::cout << std::flush;
}

References


]]>
http://phresnel.org/blog/2009/04/this-is-not-only-a-matter-of-style/feed/ 2