Martin's Tex-Blog

Posts on programming and generally technical topics

Docker: how to curl from one container into another

leave a comment »


I have a docker compose file that is similar to the following one:

version: "3"
services:
    web:
        image: nginx
        ports:
            - "80:80"
        volumes:
            - ./volumes/www/app1.example.com/html:/var/www/app1.example.com/html:z
            - ./volumes/www/app2.example.com/html:/var/www/app2.example.com/html:z
            - ./volumes/www/app3.example.com/html:/var/www/app3.example.com/html:z
        restart: always
    cron:
      build:
        context: .
        dockerfile: cron-dockerfile
      links:
        - php
        - web
    php:
      # unimportant
    db:
      # unimportant

as you see I have a web container with nginx serving webpages from three virtual hosts. For each I have a domain name specific to application name. I also have a cron container which is supposed to do some maintance jobs from time to time. It does it by executing some php script on web server. Before migrating to docker I used basicly:

 curl http://app1.example.com/some_maintance.php 

But with docker I always get host unreachable error.

After some investigation I found that I am able to ping app1.example.com from cron container but curl or wget does not reach it, also web which is supposed to be a link to nginx container from cron container has different ip than actual app1.example.com (for which I have registrated domain with physical ip address). I have access to any other domain names – http://www.google.com etc. is accessible by curl.

So the first solution I tried was to update \etc\hosts on cron container, I added 1.2.3.4 app1.example.com entry, where 1.2.3.4 is IP address of web container. And it worked. The problem is that from what I know modifying \etc\hosts is not encouraged by docker community. Instead you should use extra_hosts in docker compose yaml file, but you can specify in extra_hosts only explicit IP addresses, you cannot use container name (like web in my configuration). From what I know, if you need such feature then it is a sign you should start using custom networks. I tried to use custom networks but unfortunately with no luck.

Finally what worked was to make curl use IP address of my web container (where I can put web), and then pass domain name as -H parameter. So the command looks as follows:

curl -H'Host: app1.example.com' web/some_maintance.php
Advertisement

Written by Marcin

September 19, 2017 at 3:48 pm

Posted in Uncategorized

Tagged with

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();
}

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

Linkage of templates

leave a comment »


I would like to share observation of another non standard behavior found in Visual Studio compiler. According to C++ Templates Complete Guide: “class templates cannot share a name with a different kind of entity”, below code:

int X;
template
class X {    
};

gives following error with g++ 4.9:


main.cpp:8:7: error: 'template struct X' redeclared as different kind of symbol
class X {
^
main.cpp:6:5: note: previous declaration 'int X'
int X;

but with VS2013 compiles just fine.

Written by Marcin

December 28, 2014 at 2:24 am

Posted in Uncategorized

Be carefull with subnormal floats

leave a comment »


Subnormal floating point numbers are values that are very small (.0f to ~.1f), operations on them are specially treated by CPUs. Below is a timing of simple sumation of floating point values, you can see that once subnormal values are used, performance instantly drops 10 or more times.

http://coliru.stacked-crooked.com/a/6ffe763ab4b5ada0

// Example code for testing subnormal float efficency
float f = 2.0f;
std::chrono::steady_clock::duration prevdiff;
for (int k = 0; k < 10000; ++k) {
  float sum = .0f;		
  auto start = std::chrono::steady_clock::now();

  for (int n = 0; n < 1e7; ++n) {
    sum += f * 0.1f;  // interesting, but simple summation show no performance degradation
  }

  auto end = std::chrono::steady_clock::now();
  auto diff = end - start;
  std::cout << k << ", f=" << f << ", isnormal=" << std::isnormal(f)
    << ", elapsed=" << std::chrono::duration_cast<std::chrono::milliseconds>(diff).count() << "ms" <<
    ", ratio=" << (prevdiff.count() == 0 ? 0 : (diff.count() / prevdiff.count())) << std::endl;
    prevdiff = diff;

   if (f < std::numeric_limits<float>::min())
     break;

    f /= 2.0f;
}

here is the interesting part from the output:

123, f=1.88079e-37, isnormal=1, elapsed=69ms, ratio=1
124, f=9.40395e-38, isnormal=1, elapsed=799ms, ratio=11 <-------- here performance drop
125, f=4.70198e-38, isnormal=1, elapsed=800ms, ratio=1
126, f=2.35099e-38, isnormal=1, elapsed=800ms, ratio=0
127, f=1.17549e-38, isnormal=1, elapsed=796ms, ratio=0
128, f=5.87747e-39, isnormal=0, elapsed=985ms, ratio=1

whats interesting is that this drop happens before std::isnormal returns true. You can use _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); to make CPU not do computations using subnormal values.

This post is based on following SO : http://stackoverflow.com/questions/9314534/why-does-changing-0-1f-to-0-slow-down-performance-by-10x.

Written by Marcin

December 21, 2014 at 4:40 pm

Posted in 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++