четверг, 17 ноября 2016 г.

Использование is_base_of и enable_if и детектирование типов во время компиляции

Допустим у нас есть некая функция, которая должна быть определена только для наследников определенного класса. Можно сделать это в рантайме, но детектирование типов в рантайме это дорого и к тому же некрасиво. C++11 предлагает более красивое решение.
#include <iostream>
#include <type_traits>
 
class A 
{
public:
    virtual void do_work() = 0;
};
 
class B : public A 
{
public:
    void do_work() override { std::cout << "B::do_work()" << std::endl; };
};
 
class C
{
public:
    void do_work() { std::cout << "C::do_work()" << std::endl; };
};
 
template<typename T>
typename std::enable_if<std::is_base_of<A, T>::value, void>::type
execute_work(T &t)
{
    t.do_work();
}

UPD 03.12.2016:

можно сделать это гораздо проще:
//...
template<typename T>
bool execute_work(T &t)
{
    static_assert(std::is_base_of<A, T>::value, "T must be subclass of A");
    t.do_work();
}
 
int main()
{
    B b;
    C c;
    execute_work(b); //OK
    execute_work(c); //compile error
}
И теперь у нас компилятор будет выдавать именно то сообщение, которое мы указали в static_assert

четверг, 10 ноября 2016 г.

Передача определений прекомпиляции из cmake

Довольно частая задача, чтобы например подключать те или иные заголовки и делать это можно конечно только во время прекомпиляции.
Допустим есть такой CMakeLists.txt файл:

set(MYTARGET  "target")
# we have some string var that we want to convert to correct define for pre-compiler
set(INTERFACES_VERSION_STR  "-2016.10.23-" )

# remove all points (".")
string(REPLACE "."   ""   MY_INTERFACES_VER   ${INTERFACES_VERSION_STR})
# remove all "-" symbols
string(REPLACE "-"   ""   MY_INTERFACES_VER   ${MY_INTERFACES_VER})
# print them
message(STATUS "INTERFACES_VERSION_STR  ${INTERFACES_VERSION_STR}")
message(STATUS "MY_INTERFACES_VER   ${MY_INTERFACES_VER}")

add_library(${MYTARGET} my_source.cpp)

add_definitions(-DMY_INTERFACES_VER=${MY_INTERFACES_VER})

Тогда в исходном файле пишем:

//...
#if MY_INTERFACES_VER==20161023
#include "v20161023/include/interfaces.h"
    std::cout << "---- MY_INTERFACES_VER==20161023 ---" << std::endl;
#else
#include "mainline/include/interfaces.h"
    std::cout << "do some by default " << std::endl;
#endif