2015-03-22 3 views
5

Предположим, у меня есть время измерения класс, параметризуемым по типу длительности, как этотПолучить имя типа времени в хроно

template<typename TimeT = std::chrono::milliseconds> 
struct measure 
{ /* implementation */ }; 

То, что я хочу, чтобы иметь возможность распечатать TimeT. Я склоняюсь к реализации статической функции-члена, как это:

static string TimeType() const; 

Мои вопросы:

  1. Должен ли я добавить элемент вместо этого? Если это не статично?
  2. Как должно быть реализовано тело этого? Должен ли я использовать зависимое от реализации значение, не компилируемое время typeinfo/name комбо (в этом случае мне пришлось бы удалить constexpr выше), или я должен выбрать создание нескольких специализаций, которые вернут правильную строку в тип времени?
  3. Есть ли более стандартный/идиоматический способ получения имени типа времени?
+0

Стандартный способ получить «имя» типа использует ['type_info'] (http://en.cppreference.com/w/cpp/types/type_info) класс, возвращаемый ['typeid'] (http://en.cppreference.com/ ж/CPP/язык/TypeID). Однако в стандарте C++ ничего не говорится о том, что * может быть именем, это может быть компиляторы, искаженное имя для типа или что-то еще. –

+0

Но меня больше интересует, почему ты хочешь этого? Это похоже на [проблему XY] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). –

+0

@JoachimPileborg Я печатаю бенчмарк и просто хочу поместить заголовок в колонку времени. Я считаю, что, поскольку тип времени известен во время компиляции, я не должен повторять эту информацию в другом месте (и освободить место для обхода ошибок). В основном я использую [this] (http://stackoverflow.com/a/21995693/2567683) с более высокого уровня абстракции –

ответ

11

Вы можете использовать мой <chrono_io> library. Он состоит из одного заголовка, "chrono_io.h", который связан с документами.Пример использования будет:

#include "chrono_io.h" 
#include <iostream> 

template<typename TimeT = std::chrono::milliseconds> 
struct measure 
{ 
    TimeT value; 

    friend 
    std::ostream& 
    operator<< (std::ostream& os, const measure& m) 
    { 
     using namespace date; 
     return os << m.value; 
    } 
}; 

int 
main() 
{ 
    using namespace std::chrono; 
    measure<> m1 = {30ms}; 
    std::cout << m1 << '\n'; 
    measure<duration<int, std::ratio<1, 60>>> m2 = {duration<int, std::ratio<1, 60>>{45}}; 
    std::cout << m2 << '\n'; 
} 

, который выводит:

30ms 
45[1/60]s 
+5

SO иногда замечательно. Я имею в виду, что вы отправляете вопрос, а парень, который построил все это, отвечает ... приветствует H! –

+0

@Howard Hinnant это действительно потрясающее предложение, особенно для научных вычислений. Любая вероятность, что библиотека превратится в C++ 17? Кажется, что он уже находится в состоянии (или был предназначен) http://www.boost.org/doc/libs/1_54_0/boost/chrono/chrono_io.hpp – vsoftco

+0

@vsoftco: Спасибо за ваш комментарий.Я не уверен, могу ли я получить его на C++ 17 или нет. И как публичное объявление, если кто-то еще захочет забрать это и работать с ним в комитете, это тоже здорово. –

2

Оба duration и time_point имеют period элемент типа ratio, который представляет количество секунд в тик типа.

Я не верю, что стандарт C++ предлагает способ преобразования специальных полномочий 10 в метрические префиксы; вам придется сворачивать свои собственные функции для этого. Но имейте в виду, что этот период не должен быть ни одним из стандартных; пользователь может создавать измерения времени на основе любого периода, который им нравится (например, лет) или даже стандартных периодов, но с другим типом представления (например, double), поэтому вы, вероятно, не должны предполагать. Почему бы не сделать его еще одним параметром?

6

Способ сделать это специализируется на типе времени; таким образом, не портативность typeid.name() перестает быть фактором:

/// get the name of the chrono time type 
template<typename T> string time_type()     { return "unknown";  } 
template<> string time_type<std::chrono::nanoseconds >() { return "nanoseconds"; } 
template<> string time_type<std::chrono::microseconds>() { return "microseconds"; } 
template<> string time_type<std::chrono::milliseconds>() { return "milliseconds"; } 
template<> string time_type<std::chrono::seconds  >() { return "seconds";  } 
template<> string time_type<std::chrono::minutes  >() { return "minutes";  } 
template<> string time_type<std::chrono::hours  >() { return "hours";  } 

это д не получил много внимания. Я отправил ответ в виде мин основания для сравнения качества кода

Ofcourse трудного случая здесь, будет иметь эту информацию во время компиляции, которая потребовала бы compile time strings п»stuff

другой версии выше будет be

2

То, что вы пытаетесь сделать, это часть определения reflection, более конкретно запускать информацию о типе времени (RTTI), что дает код в способность исследовать себя во время выполнения, я хорошо посмотрел на это некоторое время назад, пытаясь создать систему, которая будет сериализовать все переменные-члены переданного типа в формате, таком как { "varName"=<varValue> }

Unfortunat простой ответ заключается в том, что C++ не поддерживает рефлексию, и там, где она обеспечивает «аналогичную» функциональность (т. <type_traits> и typeid()) оставляет желать лучшего. Наилучшие результаты будут получены на этапах пользовательской сборки, которые генерируют нужные вам данные. Я решил отказаться от этого подхода, поэтому не может реально помочь с «как» в этом случае, но эти подходы, очевидно, ограничены в переносимости.

Однако подход специализации шаблонов, о котором вы уже упоминали, является шагом на пути к наилучшей реализации, которую я видел еще для отображения времени выполнения C++, которая использует комбинацию макросов для генерации дескрипторов классов.

МФЦ макросы DECLARE_DYNAMIC и IMPLEMENT_DYNAMIC все загрязнения необходимо создать один из этих дескрипторов для вашего класса, который затем добавить функции IsKindOf(), GetRuntimeClass(), etc., самый полезный часто будучи GetRuntimeClass(), которая возвращает CRuntimeClass.

Чтобы реализовать что-то подобное, вы могли бы использовать что-то вдоль линий;

#define MakeClassDescriptor(classname) \ 
private: \ 
class classname ## Descriptor \ 
{ \ 
public: \ 
    static const char* GetName() { return #classname; } \ 
}; \ 
public: \ 
    typedef classname ## Descriptor ClassDescriptor; 

class Test 
{ 
public: 
    Test() {}; 

    MakeClassDescriptor(Test); 
}; 

Который затем позволит вам получить доступ к имени через Test::ClassDescriptor::GetName()

Там в конечно другие подходы и ваши собственные спецификации диктуют, как можно реализовать это, для примера подход, при котором классы наследуют от шаблонного Класс RTTI рассмотрит статью «Использование шаблонов для отражения на C++», написанную Домиником Филионом в книге «Программирование игр». 5

+0

+1. Отличная презентация технологий и сбор ссылок. Поздравляю с вашим блогом; В то время я также пишу что-то подобное (платформа сравнения), возможно, вам было бы интересно прочитать его, когда он будет готов –

+0

Спасибо, и, конечно, пришлите мне несколько ссылок, когда вы разместили его. –

+0

Просто отправлено [здесь] (https://ngathanasiou.wordpress.com/2015/04/01/benchmarking-in-c/) –

 Смежные вопросы

  • Нет связанных вопросов^_^