Martin's Tex-Blog

Posts on programming and generally technical topics

Archive for the ‘C++’ Category

Simple introduction of SFINAE use to fix overloading issues when using forwarding references.

leave a comment »


You have probably read on it in stackoverflow answer, or maybe one of your friends have given you an advice to “SFINAE away those overloads” to fix the overload resolution problems. The SFINAE stands for Substitution Failure Is Not An Error, and in that form is present in the C++ standard. Without this concept it would not be possible to choose correct overloads, consider this example:

http://coliru.stacked-crooked.com/a/79ec2049db08566a

//#1
template<typename T> typename T::value_type foo(T t) {
    // accepts types containing type member of name value_type
    std::cout << "typename T::value_type foo(T t)\n";
    return typename T::value_type{};
}
//#2
int foo(int t) {
    std::cout << "int foo(int t)\n";
    return 0;
}

int main()
{
    foo(1);
    foo(std::vector<int>{});
}

using overload #1 with int type is obviously an error (there is not such thing as int::value_type), but when compiler considers this overload it does not issue an error but only removes this candidate from the list of valid overloads. This is substitution failure is not an error rule in action.

Now lets go back to the topic, with C++11 we have whats called forwarding references, which allow function templates to bind to nearly all types and pass them further. The problem is that they are quite greedy monsters and when you want to overload them with some other types, there is a great chance the overloads will not get called. One of the solutions to this problem is to use tag dispatch. Example on how to use it is presented in below code.

First I present the problem when, greedy eat_all_monster template function with forwarding reference, takes it all. Even thought you would like eat_all_monster(1) to call float overload, it will not happen.

Then there is a code which assigns a type tag to each group of types assigned to specified function overloads. This way you have full control over which overload should be called for which type.

http://coliru.stacked-crooked.com/a/e13dee36eb479174

#include <iostream>
#include <string>
#include <type_traits>

// Version without tag dispatch, shows that for certain types universal 
// reference function overload will steal all calls.
template<typename T>
void eat_all_monster(T&& t) {
    std::cout << t << ", void eat_all_monster(T&& t)\n";
}

void eat_all_monster(float f) {
    std::cout << f << ", void eat_all_monster(float f)\n";
}

void eat_all_monster(const std::string& s) {
    std::cout << s << ", void eat_all_monster(std::string t)\n";
}

void test1() {
   int n = 101;
    std::string s = "123";
    eat_all_monster(n);
    eat_all_monster(s);
    eat_all_monster("12345");
    
    // Above will all call universal reference version of eat_all_monster. 
    // No special overloads will get called.
    //
    // 01, void eat_all_monster(T&& t)
    // 123, void eat_all_monster(T&& t)
    // 12345, void eat_all_monster(T&& t)    
}

// Now, to fix it we will use tag dispatch.

// This is a general tag.
using tag_for_all = std::integral_constant<int, 0>;

// Now, a tag for values, integers, shorts, floats etc.
using tag_for_values = std::integral_constant<int, 1>;

// Tag for texts, const char*, char arrays, std::string
using tag_for_texts = std::integral_constant<int, 2>;

// General trait, will catch all non values, or non texts
template<typename T> struct eat_trait { using tag = tag_for_all; };

// Below two are for specialization for which we have special overloads
template<> struct eat_trait<float>       {    using tag = tag_for_values; };
template<> struct eat_trait<int>         {    using tag = tag_for_values; };
template<> struct eat_trait<std::string> { using tag = tag_for_texts; };
template<> struct eat_trait<const char*> { using tag = tag_for_texts; };

template<typename T>
void eat_some_monster_impl(T&& t, tag_for_all) {
    std::cout << t << ", void eat_some_monster_impl(T&& t)\n";
}

void eat_some_monster_impl(float f, tag_for_values) {
    std::cout << f << ", void eat_some_monster_impl(float f)\n";
}

void eat_some_monster_impl(const std::string& s, tag_for_texts) {
    std::cout << s << ", void eat_some_monster_impl(std::string t)\n";
}

template<typename T>
void eat_some_monster(T&& t) {
    // decay_t is needed because for lvalue-s, T will be a reference (T&), 
    //         and float& and float are two different types
    //         Actually it strips references, cv-qualifications 
    //         (const volatile), and also turns char array to 
    //         pointer to char.
    eat_some_monster_impl(std::forward<T>(t), 
        typename eat_trait<std::decay_t<T>>::tag{});
}

void test2() {
    int n = 101;
    std::string s = "123";
    
    // Now version with tag dispatch will choose the appropriate 
    // overloads based on tags from type traits.
    std::cout << "\n";
    eat_some_monster(n);        // calls value overload (tag_for_values)
                                //  which accepts all values as float
    eat_some_monster(1.0f);     // -- // --
    eat_some_monster(s);        // calls text overload (tag_for_texts) 
                                //  which accepts all texts as std::string 
                                //  (they will convert to it)
    eat_some_monster("12345");  // -- // --
    eat_some_monster((void*)0x1234); // No special overload for void*, so 
                                     //  general version will be called with 
                                     //  tag: tag_for_all    
    
    /*
    // Output is exactly as expected:
    101, void eat_some_monster_impl(float f)
    1, void eat_some_monster_impl(float f)
    123, void eat_some_monster_impl(std::string t)
    12345, void eat_some_monster_impl(std::string t)
    0x1234, void eat_some_monster_impl(T&& t)
    */
}

int main()
{
    test1();
    test2();
}

Advertisements

Written by Marcin

March 14, 2017 at 1:04 am

Posted in C++

Platform dependend overload resolution ambiguity

leave a comment »


Here I will show case when types used internally by compiler might cause ambiguities in overload resolution. Below is example code:

#include <string>
struct CoolString {
    std::string s;
    CoolString(const char* p) : s(p){}
    char& operator[](size_t i) { return s.at(i); }
   operator char*() { return &s[0]; }
};

int main()  {
    CoolString ss("asd");
    ss[1] = '1';  // {1}
}
  

It looks valid, althought use of implicit user conversion operator to char* is a sign of bad design (std::string provides c_str instead). Above code compiles under g++ and clang, but fails to compile under Visual Studio. The error is that call {1} is ambiguous, and looks like below:

2>c:\prj\test.cpp(10) : error C2666: 'CoolString::operator []' : 2 overloads have similar conversions
2>        c:\prj\test.cpp(10): could be 'char &CoolString::operator [](size_t)'
2>        or 'built-in C++ operator[(char *, int)'
2>        while trying to match the argument list '(CoolString, int)'

so, compiler is unable to decide which one of those to choose:

ss.operator[](1) // line 1
ss.operator char*()[1] // line 2

In case of second choice ( line 2 ), compiler wants to apply built in subscript operator after user defined conversion to char*. Built in subscript operator takes index as a ptrdiff_t type. Because this is a typedef, lets check how it differs under g++/clang from VS:

std::cout << "size_t = " << typeid(size_t).name() << std::endl; // VS2013: unsigned int, g++: unsigned long
std::cout << "ptrdiff_t = " << typeid(ptrdiff_t).name() << std::endl; // VS2013: int, g++: long

Under VS ptrdiff_t is int, while under g++/clang its long. While size_t is always unsigned. Lets look what conversions are required by both candidates:

ss.operator[](1) – here only integral promotion of int to unsigned int or unsigned long is required

ss.operator char*()[1] – here on VS only user defined conversion must be applied to ss (so that operator char*() is called), since 1 is an int it matches ptrdiff_t which under VS is also int. But under g++/clang two conversions are requried: first user defined to char*, and then promotion of int to long.

Now its clear why VS shows error, implicit conversions sequences are ambiguous – both are of same lenghts, also they differ on different positions, but I am not clear about it here (exact standard wording) – you could argue that integral promotion should be more promoted than user defined conversion.

Under g++/clang built in operator is not choosen because it requires two implicit conversions, first is user defined conversion, second is promotion int to long. So compiler choses ss.operator[](1) which requires only integral promotion.

The solution is to:
1. Dont use implicit conversion operator to char*
2. Replace size_t with int in char& operator[](size_t i), this will make it a perfect match and top priority candidate.
3. Use ss[1u]

For more references:
http://stackoverflow.com/questions/1726740/c-error-operator-2-overloads-have-similar-conversions
– “C++ Templates – The Complete Guide” – B.2.1

Written by Marcin

January 17, 2015 at 3:10 am

Posted in C++, Uncategorized

Friend definition – or friend functions defined inside class body

leave a comment »


This is a slightly less known feature of C++ which allows you to define a function that can be called only by using Argument Dependent Lookup (ADL). Compiler will create non-member function in the namespace surrounding class where it is defined. This is how it looks like:

namespace Forest {
class CTree {
public:
CTree(int) {}

// This parameter less foo function is actually unaccessible
friend void foo() {}

// This one is accessibly only through ADL
friend void foo(const CTree&) {}
};
}

Forest::CTree tree(0);
foo(tree); // ok - call by ADT
//foo(); // error
//foo(0); // error - foo is not considered as candidate using ADL due to required implicit conversion
//Forest:foo(); // error
//Forest::foo(tree); // error
//Forest::foo(); // error

So, how is that usefull to us? It allows you to call a foo function without qualifying it with namespace name. It makes greater sense in case of operator definitions. If you define operator== as a friend inside class body, then it will get called only by ADL – as it should, and it will also have full access to your class private data. Coders mostly define binary operators as a free function to allow for implicit conversions of arguments. The problem with friend defined operator is that implicit conversion will not happen.

references:
http://stackoverflow.com/questions/8207633/whats-the-scope-of-inline-friend-functions
http://stackoverflow.com/questions/381164/friend-and-inline-method-whats-the-point

Written by Marcin

January 11, 2015 at 1:08 am

Posted in C++

Implicit type conversions with templates

leave a comment »


Suppose you want to write a template class X that must allow for operations like X = X + Y or X = Y + X, where Y is any type like int, float or other class type. How you want to start with that? Normally you would write operator+ as a free function and add it as a friend to X. Lets assume we want Y to be an int. Below code seems to solve this scenario:

template<typename T>
class X {
public:
  int n;
  X(int rn) : n(rn) {}
  template<class U>
  friend X<U> operator+(const X<U>& lhs, const X<U>& rhs);
};

template<typename U> 
  X<U> operator+(const X<U>& lhs, const X<U>& rhs) {
    X<U> ret(0);
    ret.n = lhs.n + rhs.n;
    return ret;
  }

int main() {
  X<int> a = 1;
  X<int> b = 2;
  X<int> c = a + b;
  c = c + 1;
  c = 1 + c;
  std::cout << "X : " << c.n << std::endl;
}

unfortunately this will result in errors (compilation using clang):

source_file.cpp:25:7: error: invalid operands to binary expression ('X<int>' and 'int')
c = c + 1;
    ~ ^ ~
source_file.cpp:15:7: note: candidate template ignored: could not match 'X<type-parameter-0-0>' against 'int'
X<U>& operator+(const X<U>& lhs, const X<U>& rhs) {
      ^
...

the problem is that template operator+ is not considered as a valid overload. In case of function templates, compiler will perform type deduction on the arguments and come up with a template parameter types that will match the call or else it will remove such function from list of potential candidates. Whats important here is that no implicit conversions will be done. So to make above code compile we would have to change class usage to:

c = c + X<int>(1);
c = X<int>(1) + c;

this way, there is no need for implicit conversion using X(int rn) constructor. But this is not what we want. The solution is to use a language feature that enables you to define a non-member friend function inside template class definition, as in the following example:

template<typename T>
class X {
public:
int n;
X(int rn) : n(rn) {}

friend X operator+(const X& lhs, const X& rhs) {
    X ret(0);
    ret.n = lhs.n + rhs.n;
    return ret;
}

};

int main() {
  X<int> a = 1;
  X<int> b = 2;
  X<int> c = a + b;
  c = c + 1;
  c = 1 + c;
  std::cout << "X : " << c.n << std::endl;
}

Now this compiles and outputs X: 5. Lets analyse what friend X operator+(const X& lhs, const X& rhs) means. First, X is the same as X<T>, due to class name injection (within the scope of a class template X with template parameters P1, P2, … the name of that template (X) can be equivalent to the template-id X<P1, P2, …>). Second thing is that compiler will generate for any used template parameter type a free non-template function at namespace level (outside of class X) which will be used during normal function call. Whats important for us here is that compiler will perform implicit conversions on its arguments. Such functions will be generated always, even if not used by given class instantiation. Below is example of such compiler generated free function:

X<int> operator+(const X<int>& lhs, const X<int>& rhs) {
    X<int> ret(0);
    ret.n = lhs.n + rhs.n;
    return ret;
}

This is not a new feature in C++, I suppose its c++98 wording is easier to understand.

C++98 [temp.friend]p5: When a function is defined in a friend function declaration in a class template, 
the function is defined at each instantiation of the class template. The function is defined even if it is never used.

C++11 [temp.friend]p4: When a function is defined in a friend function declaration in a class template, 
the function is instantiated when the function is odr-used. The same restrictions on multiple declarations
and definitions that apply to non-template function declarations and definitions also apply to these implicit definitions.

Written by Marcin

January 3, 2015 at 2:54 am

Posted in C++

Default template parameter redeclaration

leave a comment »


[temp.param]/12 Clearly states :

A template-parameter shall not be given default arguments by two different declarations in the same scope.

now, both clang and g++ generates errors for following code:

template<class T = int> class X;
template<class T = int> class X {};

msvc on the other hand (even with no extensions enabled) compiles it fine, I had to change second default parameter from int to some other type to see error. So its not that really bad, but still ‘shall not’ means ‘is not allowed’ as per ISO/IEC Directives. msvc on the other hand gives error in similar case but with redeclaration of function default parameter values.

Written by Marcin

December 31, 2014 at 12:17 am

Posted in C++

String literal as non type template parameter

leave a comment »


Unfortunately it is not possible to have template with string literal as a non type parameter. Until C++11 reason was that string literals had internal linkage, while non type template parameters allowed only external linkage pointers. It makes sense because templ_class should have the same typeid in all translation units. It kind of could work with string pooling enabled – which is availabe for both gcc and msvc. After C++11 the reason is more of that string literals does not match any of the allowed entities as template parameter.

You can use character array initialized with string literal as non type parameter. It compiles both with g++ and msvc:

#include <typeinfo>

template<const char* STR>
class MyStr {};

extern const char my_string[]; const char my_string[] = "alfabet";
extern const char my_string2[]; const char my_string2[] = "alfabet";

// or use constexpr
//constexpr const char my_string[] = "alfabet";
//constexpr const char my_string2[] = "alfabet";

extern const char* my_string_pc;
const char* my_string_pc = "alfabet";

int main(){
   
    // This fails with:
    //  main.cpp:30:31: error: 'my_string_pc' is not a valid template argument because 'my_string_pc' is a variable, not the address of a variable
    //    typedef MyStr<my_string_pc> str_type3;
    typedef MyStr<my_string_pc> str_type3;     
   
    // Below compiles, but gives different types
    typedef MyStr<my_string> str_type1;   
    typedef MyStr<my_string2> str_type2; 
   
    // This fails
    static_assert(std::is_same<str_type1, str_type2>::value, "");
   
    return 0;
}

EDIT:
After writing it I have found in standard ([temp.arg.nontype]) the actual reasoning for all above:

[ Note: A string literal (2.14.5) does not satisfy the requirements of any of these categories and thus is not
an acceptable template-argument. [ Example:

template<class T, const char* p> class X {
/ ... /
};
X<int, "Studebaker"> x1; // error: string literal as template-argument
const char p[] = "Vivisectionist";
X<int,p> x2; // OK

—end example ] —end note ]

refs:
http://stackoverflow.com/questions/5547852/string-literals-not-allowed-as-non-type-template-parameters

Written by Marcin

December 30, 2014 at 12:56 am

Posted in C++, Uncategorized

Dependent base class name lookup (c++ template complete guide)

leave a comment »


If you were reading c++ template complete guide : “5.2 using this->” you probably tried to test following example:

template<typename T>
class Base {
public:
  void exit() {}
};

template<typename T>
class Derived : public Base < T > {
public:
	void callMe() {
	  exit();
	}
};

if you done it under Visual Studio, you have probably realized that it does compile with no errors or warnings, so what is going on here. Your next step should be to test it with gcc or clang compiler, you would see errors now.

The problem is that VS does not implement two phase name lookup. I have found that in VS2013 diabling language extensions with /Za actually causes above code to fail to compile.

some usefull links below
http://blog.llvm.org/2009/12/dreaded-two-phase-name-lookup.html
http://stackoverflow.com/questions/11405/gcc-problem-using-a-member-of-a-base-class-that-depends-on-a-template-argument
http://clang.llvm.org/compatibility.html#dep_lookup_bases

Written by Marcin

December 16, 2014 at 11:24 am

Posted in C++