2016-01-08 3 views
1

У меня есть функция шаблона, которая может возвращать разные типы.C++: возможно ли создать функцию шаблона, возвращающую значение null?

template <class typ> 
typ GetRespVal_byField(const std::string & _fname){ 
for (pqxx::result::const_iterator row = m_result.begin(); 
    row != m_result.end(); 
    ++row) 
    { 
     if (!row[_fname].is_null()) 
      return row[_fname].as<typ>(); 
     else 
      return NULL; //this is what i want 

    } 
} 

Правильно ли это реализация?

+5

Задать компилятор ... – YSC

+0

он компилируется, но я не уверен, если это правильный способ сделать это .. –

+0

только тот, кто может определить, является ли это «правильный способ сделать это» это ты. Потому что только вы могли бы знать, что является правильным поведением для вашего собственного кода. –

ответ

3

Насколько typ может принимать NULL значение (или если typ объект может быть построен из значения NULL), да, вы можете. Если type является указателем или int, например.

Вы даже можете вернуть foo_bar .... если foo_bar является действительным typ значения, оно будет работать ....

разрешения шаблона делается при компиляции, так как прокомментировал МКЦ, если он собирает, то да, это разрешено с точки зрения проверки типа (теперь тот факт, что компиляция кода не обязательно означает, что она будет работать во время выполнения, но для вашего конкретного вопроса это достаточно хорошо).

+0

Это не совсем так. Компиляторы могут свободно компилировать код с неопределенным поведением. –

+0

@ChristianHackl: Правильно, но он не будет компилироваться, если типы несовместимы. Обновлено мое сообщение. – jpo38

2

это возможно создать функцию шаблона, возвращающую значение null?

Как правило, да, конечно. Почему функция шаблона не должна это делать?

Однако ...

ли это правильное применение?

Это зависит от вашего определения «правильной» :)

Например, если вы пытаетесь создать экземпляр функции с std::string для typ, а затем возвращение NULL вызывает неопределенное поведение (потому что вы бы попытаться построить std::string от нулевой указатель). Неопределенное поведение обычно считается очень неправильным.

Рассмотрите Boost.Optional как альтернативу для представления о существовании чего-то. Это более общий, чем NULL.

1

В более общем плане, скомпилирование шаблона не очень много. Microsoft только недавно abandoned something можно грубо назвать реализацию замены текста для шаблонов:

Метод, выбранный для реализации этой [шаблонов, в старом компиляторе] должен был сделать некоторый минимальный парсинг шаблона, а затем захватить всю template как строка токенов (это очень похоже на то, как макросы обрабатываются в компиляторе). Позже, когда экземпляр шаблона создается,, что поток токенов будет воспроизводиться через парсер и аргументы шаблона будут заменены.

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

Это яркий контраст с C#, который компилирует автономные шаблоны в строгом смысле слова (к IL, конечно).

Инстанцирование шаблон делает больше:

#include<iostream> 

using namespace std; 

// this works; 
template<typename T> T f(T t) 
{ 
    return cout; 
}  

// this doesn't 
// double d = f(1.0); 
0

Вы могли бы написать признака класса типа, который бы определить NULL для любого типа вы используете. Я полагаю, у вас возникнет проблема с этим - какой NULL вы указали бы для std::string? Вы можете изменить свою подпись функции и вернуть std::pair<typ, bool> где:

  1. если не значение NULL возвращается, то first равно возвращаемое значение и second в true.
  2. , если значение NULL должно быть возвращено, то первое равно по умолчанию инициализирован станд и second является false
2

Это возможно, но не всегда может быть хорошей идеей. Например, если typ является string, тогда ваш код будет компилироваться, потому что NULL будет интерпретироваться как char *, из которого неявно будет построена строка. Однако код будет терпеть неудачу во время выполнения, когда удаляется ветвь else, потому что попытка создания строки из NULL - это неопределенное поведение, которое почти наверняка приведет к нарушению доступа.

Поэтому я бы предложил по крайней мере два улучшения вашего кода.

  1. черты Использование типа в сочетании с static_assert, чтобы гарантировать, что typ является тип указателя. Добавьте это в функцию шаблона:

    static_assert(is_pointer<typ>::value, "<typ> must be a pointer type"); 
    

    Это исключает типы, которые не являются указателями, но конструктивны из указателя, и дополнительно делает сообщение об ошибке более понятными для пользователя.

  2. Возвращение nullptr, а не NULL - в основном, чтобы сделать намерение более четко, но и избежать гипотетических сценариев, когда переход к интегральному типу будет плохо (в отличие от NULL, nullptr не неявно преобразуется в целочисленных типов).