Extern "C", variadic template

0

2 pytania:
Question 1: Jak wywolac w ANSI C taki program w C++:

#include <iostream>
#include <string>
#include <limits>

using std::string;
using std::cerr;

#define LOG_FUNC(x) cerr << '\n' << #x " = " << x << '\t'
#define LOG_ARG(x) cerr << #x " = " << x << '\t'

template <typename T>
class Money {
static_assert((std::numeric_limits<T>::is_integer || std::is_floating_point<T>::value) && "Number required.");
public:
   Money(const string & dollars, const long double cents);   
   Money(const string & dollars); 

   static Money create(const string & dollars, const long double cents);
   static Money create(const string & dollars);
};

template <typename T>
Money<T>::Money(const string & dollars, const long double cent) {
   LOG_FUNC(__func__);
   LOG_ARG(dollars);
   LOG_ARG(cent);
}

template <typename T>
Money<T>::Money(const string & dollars) {
   LOG_FUNC(__func__);
   LOG_ARG(dollars);
}

template <typename T>
Money<T> Money<T>::create(const string & dollars) {   
   LOG_FUNC(__func__);
   LOG_ARG(dollars);
   return Money<T>(dollars);
}

template <typename T>
Money<T> Money<T>::create(const string & dollars, const long double cents) {
   LOG_FUNC(__func__);
   LOG_ARG(dollars);
   LOG_ARG(cents);
   return Money<T>(dollars, cents);
}

template <typename T>
struct Creation {
	template<typename... Args>
	Money<T> operator()(Args...args) const {
		return Money<T>::create(std::forward<Args>(args)...);
	}
};

template <class Type, template<typename> class Template>
struct Constructor {
	template<typename... Args>
	Template<Type> operator()(Args...args) const {
		return Template<Type>(std::forward<Args>(args)...);
	}
};

template <typename Function, typename... Args> 
void call(Function && f, Args &&... args ) { 
   f(std::forward<Args>(args)...);
}

int main() {
   call(Constructor<int, Money>(), "-20.8", 5.0L);
   call(Constructor<long long, Money>(), "78");
   call(Creation<unsigned long long>(), "2", 5);
   call(Creation<long double>(), "7");
   cerr << '\n';
}

// g++ -Wfatal-errors -Wall -Wextra -Wconversion -std=c++14 

probowalem z extern "C" i void*, ale poza recznym przepisywaniem kazdej klasy szablonowej czyli: Money<int>, Money<long double="double">, ...,
wszystko co spelnia warunek: static_assert((std::numeric_limits<T>::is_integer || std::is_floating_point<T>::value) && "Number required.");
to nie mam pomyslu.
Question 2: A i czy ten program w samym C++ (bez odwolywania do C) to tez mozna jakos lepiej napisac bo nie wydaje mi sie abym wyczerpal najlepsze mozliwosci

4

W jakim sensie, "wywołać z C program"? Jakiś przykład użycia można prosić?

2
teofrast napisał(a):

np. bezposrednio z funkcji int main(void) w pliku main.c

Daj konkretny przykład użycia i opisz co chcesz osiągnąć.

1

A i czy ten program w samym C++ (bez odwolywania do C) to tez mozna jakos lepiej napisac bo nie wydaje mi sie abym wyczerpal najlepsze mozliwosci

IMO najprostsze rozwiązania są zawsze najlepsze. Zobacz jak można to odchudzić.

#include <iostream>

enum class show { dollars , cents };

struct Tag
{
    Tag( std::ostream& out_ , show type_ ): out{out_} , type{type_} {}
    std::ostream& out;
    show type;    
}; 

auto operator<<( std::ostream& out , show type ){ return Tag{out,type}; }

std::ostream& operator<<( Tag tag , long double value )
{   
    if( tag.type == show::dollars ) tag.out << static_cast<long double>(value/100.0) << " dollars";
    else tag.out << value << " cents";
    return tag.out;
}

constexpr long double operator"" _dollars ( long double value ){ return value*100; }
constexpr long double operator"" _cents ( unsigned long long n ){ return n; }

int main() 
{   
   std::cout << show::dollars << -20.8_dollars+5_cents << std::endl;
   std::cout << show::cents << 2.1_dollars+78_cents << std::endl;
   std::cout << show::cents << 2.1_dollars-1.78_dollars-5000_cents << std::endl;
}

https://godbolt.org/z/sdsnPc8hq

2

Jak chcesz używać kodu z C++ z kodu w C to musisz wystawić api zgodne z C, co oznacza zabawę handlami, ifdefami, externami itd. zastanów się czy na pewno tego chcesz.

0

tak, wlasnie chce sie tego nauczyc i pisze program testowy

0

Nie zapomnij o wyjatkach. W praktyce prawie kazda funkcje trzeba bedzie opakowac w try. No i do C zwrocic kod bledu. A moze i tekst bledu. A jesli tak to moze i rozmiar bufora jesli to klient ma przydzielac pamiec.

2
teofrast napisał(a):

tak, wlasnie chce sie tego nauczyc i pisze program testowy

W takim razie wystawiasz interfejs w postaci nagłówka zgodnego z C, który otaczasz takim czymś

#ifdef __cplusplus
extern "C" {
#endif

// twoje funkcje


#ifdef __cplusplus
}
#endif

Wtedy jak skompilujesz kod C++ do binarnej biblioteki, możesz ją używać w C poprzez ten właśnie nagłówek. Nie zapomnij oczywiście o strażniku nagłówka. Implementacje tychże funkcji w pliku .cpp mogą już zawierać C++.

0

Na razie tylko czesc zrobilem i dokoncze potem (nie ma np. obslugi wyjatkow, obslugi szablonow - tylko na sztywno dla 1 Money<int> jest, a takze recznego wczytywania bibliotek wspoldzielonych przez dlopen) ale to co jest testowalem i chyba dziala:
https://github.com/carneades3/Linking

1

W sensie chcesz używać funkcjonalności napisanych w języku c++ czy chcesz odpalić plik wykonywalny?
Jeżeli plik wykonywalny to coś takiego:

#include <stdlib.h>
...
int status = system("./foo 1 2 3");

1 użytkowników online, w tym zalogowanych: 0, gości: 1