Здесь уже есть несколько отличных ответов. Вот еще одна попытка, просто для удовольствия:
function formatDollar(num) {
var p = num.toFixed(2).split(".");
return "$" + p[0].split("").reverse().reduce(function(acc, num, i, orig) {
return num=="-" ? acc : num + (i && !(i % 3) ? "," : "") + acc;
}, "") + "." + p[1];
}
И некоторые тесты:
formatDollar(45664544.23423) // "$45,664,544.23"
formatDollar(45) // "$45.00"
formatDollar(123) // "$123.00"
formatDollar(7824) // "$7,824.00"
formatDollar(1) // "$1.00"
Отредактировано: теперь оно будет обрабатывать и отрицательные числа
Концепции предназначены для полиморфизма времени компиляции, что означает параметрический универсальный код. Интерфейсы предназначены для полиморфизма во время выполнения.
Вы должны реализовать интерфейс по мере реализации Концепции. Разница в том, что вам не нужно явно указывать, что вы реализуете концепцию. Если нужный интерфейс совпадает, проблем нет. В случае интерфейсов, даже если вы реализовали все требуемые функции, вы должны возбудимость сказать, что вы это реализуете!
Я постараюсь уточнить свой ответ :)
Представьте, что вы разрабатывают контейнер, который принимает любой тип, имеющий функцию-член size . Мы формализуем концепцию и назовем ее HasSize, конечно, мы должны определить ее где-нибудь еще, но это уже не пример.
template <class HasSize>
class Container
{
HasSize[10]; // just an example don't take it seriously :)
// elements MUST have size member function!
};
Затем, Представьте, что мы создаем экземпляр нашего Контейнера и называем его myShapes , Shape является базовым классом и определяет функцию-член size . Square и Circle - его детище. Если Shape не определил размер, должна появиться ошибка.
Container<Shape> myShapes;
if(/* some condition*/)
myShapes.add(Square());
else
myShapes.add(Circle());
Надеюсь, вы видите, что Shape может быть проверен по HasSize во время компиляции , нет причин делать проверка во время выполнения. В отличие от элементов myShapes , мы могли бы определить функцию, которая ими манипулирует:
void doSomething(Shape* shape)
{
if(/* shape is a Circle*/)
// cast then do something with the circle.
else if( /* shape is a Square */)
// cast then do something with the square.
}
В этой функции вы не можете знать, что будет передано во время выполнения: Circle или Square!
Это два инструмента для аналогичной работы,
Концепции - это типы лайков (классы) для шаблонов: они предназначены только для общей программной части языка.
Таким образом, они не предназначены для замены классов интерфейсов (если вы имеете в виду абстрактных классов или другой эквивалентной реализации C ++ интерфейсов C # или Java), поскольку он предназначен только для проверки типов, используемых в параметрах шаблона, на соответствие определенным требованиям. Проверка типа выполняется только во время компиляции, как и генерация всего кода шаблона, а классы интерфейса влияют на выполнение во время выполнения.
Это более или менее разница во взглядах. Хотя интерфейс (как в C #) указывается аналогично базовому классу, концепция также может быть сопоставлена автоматически (аналогично утиной печати в Python). До сих пор неясно, на каком уровне C ++ будет поддерживать автоматическое сопоставление концепций, что является одной из причин, по которой они отказались от него.