В чем разница между значением (типом) и типом (значением)? - PullRequest
42 голосов
/ 31 октября 2009

В чем разница между

(type)value

и

type(value)

в C ++?

Ответы [ 5 ]

50 голосов
/ 31 октября 2009

Нет разницы; согласно стандарту (§5.2.3):

Спецификатор простого типа (7.1.5), за которым следует список выражений в скобках, создает значение указанного типа по заданному списку выражений. Если список выражений является одним выражением, выражение преобразования типа эквивалентно (в определенности и если определено в значении) соответствующему приведенному выражению (5.4).

Поскольку в вопросе указана разница между type(value) и (type)value, разницы нет абсолютно.

Если и только если вы имеете дело с списком значений, разделенных запятыми, разница может быть. В этом случае:

Если в списке выражений указано более одного значения, тип должен быть классом с соответствующим образом объявленным конструктором (8.5, 12.1), а выражение T (x1, x2, ...) фактически эквивалентно объявлению T t (х1, х2, ...); для некоторой изобретенной временной переменной t, результатом которой является значение t в качестве значения r.

Как указал Трубадур, есть определенные имена типов, для которых версия type(value) просто не будет компилироваться. Например:

char *a = (char *)string;

скомпилирует, но:

char *a = char *(string);

не будет. Один и тот же тип с другим именем (например, созданный с typedef) может работать, хотя:

typedef char *char_ptr;

char *a = char_ptr(string);
13 голосов
/ 31 октября 2009

Нет разницы; Стандарт C ++ (выпуски 1998 и 2003 гг.) ясно говорит об этом. Попробуйте следующую программу, убедитесь, что вы используете совместимый компилятор, такой как бесплатный предварительный просмотр на http://comeaucomputing.com/tryitout/.

#include <cstdlib>
#include <string>
int main() {
  int('A'); (int) 'A'; // obvious
  (std::string) "abc"; // not so obvious
  unsigned(a_var) = 3; // see note below
  (long const&) a_var; // const or refs, which T(v) can't do
  return EXIT_SUCCESS;
}

Примечание: unsigned(a_var) отличается, но показывает, что эти точные токены могут означать что-то другое. Он объявляет переменную с именем a_var типа unsigned и вообще не является приведением. (Если вы знакомы с указателями на функции или массивы, подумайте о том, как использовать скобки около p в типе, подобном void (*pf)() или int (*pa)[42].)

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

7 голосов
/ 11 декабря 2011

Нет разницы, когда оба являются приведениями, но иногда «тип (значение)» не является приведением.

Вот пример из стандартного проекта N3242, раздел 8.2.1:

struct S 
{
    S(int);
};

void foo(double a) 
{
    S w( int(a) ); // function declaration
    S y( (int)a ); // object declaration
}

В этом случае «int (a)» не является приведением, поскольку «a» не является значением, это имя параметра, заключенное в лишние скобки. В документе говорится

Неоднозначность, возникающая из-за сходства функционального стиля приведение и объявление, упомянутое в 6.8, также может происходить в контексте декларации. В этом контексте выбор между функцией объявление с избыточным набором скобок вокруг параметра имя и объявление объекта со стилем функции, приведенным в качестве инициализатор. Как и в случае двусмысленностей, упомянутых в 6.8, Решение заключается в рассмотрении любой конструкции, которая может быть декларация декларация.

1 голос
/ 11 февраля 2013

В c нет type (value), в то время как в c / c ++ допускаются и type (value), и (type) value.

0 голосов
/ 08 июля 2015

Чтобы проиллюстрировать ваши варианты в C ++ (только у одного есть проверка безопасности)

#include<boost/numeric/conversion/cast.hpp> 

using std::cout;
using std::endl;
int main(){

    float smallf = 100.1;

    cout << (int)smallf << endl; // outputs 100 // c cast
    cout << int(smallf) << endl; // outputs 100 // c++ constructor = c cast

    cout << static_cast<int>(smallf) << endl; // outputs 100
//  cout << static_cast<int&>(smallf) << endl; // not allowed
    cout << reinterpret_cast<int&>(smallf) << endl; // outputs 1120416563
    cout << boost::numeric_cast<int>(smallf) << endl; // outputs 100

    float bigf = 1.23e12;

    cout << (int)bigf << endl; // outputs -2147483648
    cout << int(bigf) << endl; // outputs -2147483648

    cout << static_cast<int>(bigf) << endl; // outputs -2147483648
//  cout << static_cast<int&>(bigf) << endl; // not allowed
    cout << reinterpret_cast<int&>(bigf) << endl; // outputs 1401893083
    cout << boost::numeric_cast<int>(bigf) << endl; // throws bad numeric conversion
}
...