반응형

네이버지도를 플러터에서 띄울 수 있는 플러그인입니다.

Plug-in which shows naver map on flutter project support Android and iOS.

Install 

해당 플러그인은 Naver Cloud PlatForm - map 에서 제공하는 map서비스를 Android와 iOS 환경에서 보여주는 플러그인입니다.

  • Naver cloud platform 에서 콘솔의 AI·Application Service > AI·NAVER API > Application에서 애플리케이션을 등록합니다.
  • 등록한 애플리케이션을 선택해 Client ID값을 확인하고 변경 화면에서 Maps가 선택되어 있는지 확인한다.

pubspec.yaml에 plug in dependencies에 작성

dependencies:
  naver_map_plugin: ^0.9.6

Warning 

  • 지도에서 제공하는 기본 컨트롤러가 잘 작동하지 않는 문제 (이유를 찾지 못하고 있음)
  • android는 현 위치 버튼만 정상 작동

NOTICE (Android) 

  • 한국어
    • 네이버에서 제공하는 SDK의 경우 안드로이드에서 지도를 표시하기 위해 기본값으로 GLSurfaceView를 사용한다. hot reload시에 naver map SDK의 binary에서 정확하지 않은 이유로 app crash가 발생한다. reload하지 않는 release version 에서는 성능이 더 좋은 GLSurfaceView를 사용하고, 아닌 경우 hot reload가 가능한 TextureView를 사용한다.
  • English
    • NaverMap SDK use GLSurfaceView as default to flush map view in Android. At hot reload, App crash occurs in binary file of naver map SDK caused by unclear reason. if you build released version, this plug-in use GLSurfaceView for better performance, otherwise TextureView is used to make hot-reload available.

ANDROID GETTING START 

AndroidManifest.xml에 지정

<manifest>
    <application>
        <meta-data
            android:name="com.naver.maps.map.CLIENT_ID"
            android:value="YOUR_CLIENT_ID_HERE" />
    </application>
</manifest>

naver map에서 현위치탐색 기능을 사용하기 위해서는 AndroidManifest.xml에서 권한을 명시한다.

<manifest>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
</manifest>

또한 android API level 23(M) 이상의 경우 동적 권한을 필요로 한다. 다음은 동적권한을 요청하는 예제 코드이다.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 0);
    }
}

iOS GETTING START 

대용량 파일을 받기 위해 git-lfs 설치가 필요합니다.

$ brew install git-lfs

그리고 git-lfs을 사용하기 위해 다음의 커맨드를 입력해주세요. lfs 사용 설정이 안될 경우 pod를 통한 dependency가 다운로드 되지않습니다.

$ git lfs install

info.plist에 지정

<dict>
  <key>NMFClientId</key>
  <string>YOUR_CLIENT_ID_HERE</string>
  <key>io.flutter.embedded_views_preview</key>
  <true/>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>

naver map에서 현위치탐색 기능을 사용하기 위해서는 info.plist에서 권한을 명시한다.

<dict>
    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
	<string>[USAGE PERPOSE]</string>
	<key>NSLocationAlwaysUsageDescription</key>
	<string>[USAGE PERPOSE]</string>
	<key>NSLocationWhenInUseUsageDescription</key>
	<string>[USAGE PERPOSE]</string>
</dict>

이후 AppDelefate에서 위치 사용권한을 획득하는 예제.

if (CLLocationManager.locationServicesEnabled()) {
    switch CLLocationManager.authorizationStatus() {
    case .denied, .notDetermined, .restricted:
        self.manager.requestAlwaysAuthorization()
        break
    default:
        break
    }
}       

 

샘플 코드

import 'package:flutter/material.dart';

import 'package:naver_map_plugin_example/base_map.dart';
import 'package:naver_map_plugin_example/circle_map.dart';
import 'package:naver_map_plugin_example/padding_test.dart';
import 'package:naver_map_plugin_example/marker_map_page.dart';
import 'package:naver_map_plugin_example/path_map.dart';
import 'package:naver_map_plugin_example/polygon_map.dart';
import 'package:naver_map_plugin_example/text_field_page.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MainPage(),
    );
  }
}

class MainPage extends StatefulWidget {
  @override
  _MainPageState createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  List<String> menuText = [
    '기본 지도 예제',
    '마커 예제',
    '패스 예제',
    '원형 오버레이 예제',
    '컨트롤러 테스트',
    '폴리곤 예제',
    'GLSurface Thread collision test',
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        padding: EdgeInsets.all(16),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: menuText
              .map((text) => GestureDetector(
                    onTap: () => _onTapMenuItem(text),
                    child: Container(
                      margin: EdgeInsets.symmetric(vertical: 8),
                      padding: EdgeInsets.all(16),
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(6),
                        border: Border.all(color: Colors.indigo),
                      ),
                      child: Text(
                        text,
                        style: TextStyle(
                          color: Colors.indigo,
                          fontSize: 12,
                          fontWeight: FontWeight.w600,
                        ),
                        textAlign: TextAlign.center,
                      ),
                    ),
                  ))
              .toList(),
        ),
      ),
    );
  }

  _onTapMenuItem(String text) {
    final index = menuText.indexOf(text);
    switch (index) {
      case 0:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => BaseMapPage(),
            ));
        break;
      case 1:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => MarkerMapPage(),
            ));
        break;
      case 2:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => PathMapPage(),
            ));
        break;
      case 3:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => CircleMapPage(),
            ));
        break;
      case 4:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => PaddingTest(),
            ));
        break;
      case 5:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (_) => PolygonMap(),
            ));
        break;
      case 6:
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (_) => TextFieldPage(),
          ));
    }
  }
}

 

출처: https://pub.dev/packages/naver_map_plugin

 

반응형

반응형

Flutter SDK 다운로드


  • 명시적이고 간편한 경로에 압축을 해제합니다.(예: c:\src\flutter)

 

Flutter 기본 환경변수 PATH 설정


  • C:\src\flutter 기준

 

Windows 명령 프롬프트에서 flutter --version 실행해보자.

  • Flutter 3.0.1 표시되면 기본 PATH가 잘 설정된 것이다.

 

Flutter 개발 환경 준비(for Android)


Windows 명령 프롬프트에서 flutter doctor 실행해보자.

  • 모든 개발 환경 준비가 잘 되어 있다면 "No issues found!" 메시지를 확인 할 수 있다.
  • 준비되지 않은 체크 리스트는 해결 방법이 친절하게 제시되니 참고해서 해결하도록 하자

 

Flutter Doctor 이슈 해결방법


Android toolchain - Some Android licenses not accepted

  • Android 라이선스만 동의하면 쉽게 해결된다.
    • flutter doctor --android-licenses 그대로 타이핑하자.


 

반응형

반응형

Concept의 개념

  • 일반적으로 함수 템플릿(또는 클래스 템플릿)은 모든 타입이 아니라 특정 조건을 만족하는 타입에 대해서 동작하게 됨
  • 타입이 가져야 하는 조건을 코드로 표현 한 것
  • 2000년 중반부터 이야기 되었으나 아직 표준화 되지 않음
  • C++20 표준에 추가될 예정
  • Concept 문법이 도입될 경우 템플릿 코드에 많은 변화가 있게됨
#include <iostream>
using namespace std;

struct Point
{
    int x, y;
};

// 실제 파라미터가 모든 타입이 아닌 연산자 < 가능한 타입에 대해서만 지원하는 템플릿임
template<typename T> T Min(T x, T y)
{
    return y < x ? y : x;
}

int main()
{
    Point p1, p2;
    Min(p1, p2);
}
#include <iostream>
using namespace std;

struct Point
{
    int x, y;
    bool operator<(const Point& p) { return true; }
};

// 1. concept 만들기
template<typename T>
concept bool LessThanComparable = requires(T a, T b)
{
    { a < b }-- > bool;
};

// 2. template 만들때 concept 표기
template<typename T> requires LessThanComparable<T>
T Min(T x, T y)
{
    return y < x ? y : x;
}

// 3. template 만들때 T대신 concept 사용
LessThanComparable Min(LessThanComparable x, LessThanComparable y)
{
    return y < x ? y : x;
}

int main()
{
    Point p1, p2;
    Min(p1, p2);
}
반응형

반응형

Typelist

  • 값이 아닌 타입의 리스트를 보관하는 데이터 타입

  • 템플릿 인자가 1개라도 Typelist를 활용하면 복수의 타입을 만들 수 있음

#include <iostream>
using namespace std;

// 값을 보관하지 않음
// 타입 2개를 보관함
template<typename T, typename U> struct Typelist
{
    typedef T Head;
    typedef U Tail;
};

struct NullType {};

// 매크로 도입
#define TYPELIST_1(T1) Typelist<T1, NullType>
#define TYPELIST_2(T1, T2) Typelist<T1, Typelist<T2, Nulltype>>
#define TYPELIST_3(T1, T2, T3) Typelist<T1, Typelist<T2, Typelist<T3, Nulltype>>>
#define TYPELIST_2(T1, T2, T3, T4) Typelist<T1, Typelist<T2, Typelist<T3, Typelist<T4, Nulltype>>>>

template<typename T> class xtuple {};

int main()
{
    xtuple<int> t1;

    Typelist<int, NullType> t1;
    Typelist<int, Typelist<int, NullType>> t2;
    Typelist<int, Typelist<int, Typelist<char, NullType>>> t3;
}

 

Typelist Length

  • 타입리스트의 요소 수 구하기

#include <iostream>
using namespace std;

// 값을 보관하지 않음
// 타입 2개를 보관함
template<typename T, typename U> struct Typelist
{
    typedef T Head;
    typedef U Tail;
};

struct NullType {};

// 매크로 도입
#define TYPELIST_1(T1) Typelist<T1, NullType>
#define TYPELIST_2(T1, T2) Typelist<T1, Typelist<T2, NullType>>
#define TYPELIST_3(T1, T2, T3) Typelist<T1, Typelist<T2, Typelist<T3, NullType>>>
#define TYPELIST_4(T1, T2, T3, T4) Typelist<T1, Typelist<T2, Typelist<T3, Typelist<T4, NullType>>>>

// 1. 사용하는 모습을 보고 메인 템플릿 생성
template<typename T> struct Length;

// 2. 갯수를 구할 수 있도록 부분 특수화
template<typename T, typename U> struct Length<Typelist<T, U>>
{
    enum { value = Length<U>::value + 1 };
};

// 3. 재귀를 종료하기 위한 특수화
template<> struct Length<NullType>
{
    enum { value = 0 };
};

template<typename T> void test()
{
    cout << Length<T>::value << endl; // 4
}

int main()
{
    test<TYPELIST_4(int, int, double, float)>();
}

TypeAt

#include <iostream>
using namespace std;

// 값을 보관하지 않음
// 타입 2개를 보관함
template<typename T, typename U> struct Typelist
{
    typedef T Head;
    typedef U Tail;
};

struct NullType {};

// 매크로 도입
#define TYPELIST_1(T1) Typelist<T1, NullType>
#define TYPELIST_2(T1, T2) Typelist<T1, Typelist<T2, NullType>>
#define TYPELIST_3(T1, T2, T3) Typelist<T1, Typelist<T2, Typelist<T3, NullType>>>
#define TYPELIST_4(T1, T2, T3, T4) Typelist<T1, Typelist<T2, Typelist<T3, Typelist<T4, NullType>>>>


// Typelist의 N번째 요소의 타입 구하기
// 메인 템플릿
template<typename T, int N> struct TypeAt
{
    //typedef ? type;
};

// 원하는 타입을 구할 수 있도록 부분 특수화
// N == 0
template<typename T, typename U> struct TypeAt<Typelist<T, U>, 0>
{
    typedef T type;
};

// 원하는 타입을 구할 수 있도록 부분 특수화
// N != 0
template<typename T, typename U, int N> struct TypeAt<Typelist<T, U>, N>
{
    typedef typename TypeAt<U, N-1>::type type;
};

template<typename T> void test()
{
    typename TypeAt<T, 0>::type i; // int
    cout << typeid(i).name() << endl;

    typename TypeAt<T, 1>::type c; // char
    cout << typeid(c).name() << endl;

    typename TypeAt<T, 2>::type d; // double
    cout << typeid(d).name() << endl;

    typename TypeAt<T, 3>::type l; // long
    cout << typeid(l).name() << endl;
}

int main()
{
    test<TYPELIST_4(int, char, double, long)>();
}

 

Append

#include <iostream>
using namespace std;

// 값을 보관하지 않음
// 타입 2개를 보관함
template<typename T, typename U> struct Typelist
{
    typedef T Head;
    typedef U Tail;
};

struct NullType {};

// 매크로 도입
#define TYPELIST_1(T1) Typelist<T1, NullType>
#define TYPELIST_2(T1, T2) Typelist<T1, Typelist<T2, NullType>>
#define TYPELIST_3(T1, T2, T3) Typelist<T1, Typelist<T2, Typelist<T3, NullType>>>
#define TYPELIST_4(T1, T2, T3, T4) Typelist<T1, Typelist<T2, Typelist<T3, Typelist<T4, NullType>>>>

// Typelist 끝에 타입 추가하기
template<typename TL, typename T> struct Append;

// TL T
// 1. NullType, NullType => NullType
template<> struct Append<NullType, NullType>
{
    typedef NullType type;
};

// 2. NullType, 임의의 타입 => Typelist<임의의 타입, NullType>
template<typename T> struct Append<NullType, T>
{
    typedef Typelist<T, NullType> type;
};

// 3. NullType, Typelist<Head, Tail> = Typelist<Head, Tail>
template<typename Head, typename Tail> struct Append<NullType, Typelist<Head, Tail>>
{
    typedef Typelist<Head, Tail> type;
};

// 4. Typelist<Head, Tail>, NullType => Typelist<Head, Tail>
template<typename Head, typename Tail> struct Append<Typelist<Head, Tail>, NullType>
{
    typedef Typelist<Head, Tail> type;
};

// 5. Typelist<Head, Tail>, 임의의 타입 => Typelist<Head, Append<Tail, T>::type>
template<typename Head, typename Tail, typename T> struct Append<Typelist<Head, Tail>, T>
{
    typedef Typelist<Head, typename Append<Tail, T>::type> type;
};

template<typename T> void test()
{
    typename Append<T, int>::type t1;
    cout << typeid(t1).name() << endl; // int, char, double, int, NullType
}

int main()
{
    test<TYPELIST_3(int, char, double)>();
}

 

Typelist 예제

#include <iostream>
using namespace std;

// 값을 보관하지 않음
// 타입 2개를 보관함
template<typename T, typename U> struct Typelist
{
    typedef T Head;
    typedef U Tail;
};

struct NullType {};

// 매크로 도입
#define TYPELIST_1(T1) Typelist<T1, NullType>
#define TYPELIST_2(T1, T2) Typelist<T1, Typelist<T2, NullType>>
#define TYPELIST_3(T1, T2, T3) Typelist<T1, Typelist<T2, Typelist<T3, NullType>>>
#define TYPELIST_4(T1, T2, T3, T4) Typelist<T1, Typelist<T2, Typelist<T3, Typelist<T4, NullType>>>>

// Holder : 임의 타입의 data 1개 보관
template<typename T> struct Holder
{
    T value;
};

// GenScatterHierachy => MakeCode
template<typename T, template<typename> class Unit> 
class MakeCode : public Unit<T>
{
};

template<template<typename> class Unit> 
class MakeCode<NullType, Unit>
{
};

template<typename Head,             //            , Holder<double>,     empty 
    typename Tail,                  // Holder<int>, MakeCode<double, Unit>, MakeCode<NullType>
    template<typename> class Unit>  // MakeCode<int, Unit>, MakeCode<Typelist<double, NullType>, Unit
    
class MakeCode<Typelist<Head, Tail>, Unit> : public MakeCode<Head, Unit>, public MakeCode<Tail, Unit>
{
    // int value;
    // double value;
};

int main()
{
    // MakeCode의 1번째 인자가 Typelist일때
    MakeCode<TYPELIST_2(int, double), Holder> mc1;  // 기반 클래스 Holder<int>
                                // Holder<int>와 메모리 모양이 동일
    MakeCode<double, Holder> mc2; // Holder<double>
    MakeCode<NullType, Holder> mc3; // Empty
}
반응형

반응형

Member Detect IDioms

  • 클래스의 멤버 타입 존재 여부 확인

  • 클래스의 멤버 함수 존재 여부 확인

//컴파일 타임의 함수 시그니처에 대한 특성만 활용하는 특성을 이용하는 기법

// 함수 시그니처만 사용함으로 구현부가 없어도 괜찮음
char foo(int a);
short foo(double d);

int main()
{
    int n = 10;

    cout << sizeof(n) << endl; // 4
    //cout << sizeof(foo) << endl; // Error
    cout << sizeof(foo(3)) << endl; // 1
    cout << sizeof(foo(3.3)) << endl; // 2
}
#include <iostream>
#include <vector>
using namespace std;

// 멤버 타입을 가진 데이터용 템플릿(반환값이 char로 1바이트)
template<typename T> 
char check(typename T::value_type* a);

// 멤버 타입이 없는 데이터용 템플릿(반환값이 short로 2바이트)
template<typename T>
short check(...);

// 멤버 타입이 없는 데이터
struct NoValueType
{
};
// 멤버 타입이 있는 데이터
struct HasValueType
{
    typedef int value_type;
};

// 멤버 타입 존재를 여부 확인 함수
template<typename T>
struct has_value_type
{
    // 반환값이 char(1바이트)일때는 true, short(2바이트)일때는 false
    static constexpr bool value = (sizeof(check<T>(0)) == 1); 
};

int main()
{
    cout << has_value_type<HasValueType>::value << endl;
    cout << has_value_type<NoValueType>::value << endl;

    HasValueType t1;
    cout << sizeof(check<HasValueType>(0)) << endl;
    NoValueType t2;
    cout << sizeof(check<NoValueType>(0)) << endl;
}
#include <iostream>
#include <vector>
using namespace std;

// 멤버함수가 존재할 경우 
template<typename T> 
char check(decltype(T().resize(0))* a);

// 멤버함수가 존재하지 않을 경우
template<typename T>
short check(...);

// 멤버함수 존재 체크
template<typename T>
struct has_resize
{
    static constexpr bool value = (sizeof(check<T>(0)) == 1); 
};

int main()
{
    // vector는 resize가 있으므로 true 리턴
    cout << has_resize<vector<int>>::value << endl;
    
    // array는 resize가 없으므로 false 리턴
    cout << has_resize<array<int, 10>>::value << endl;
}
반응형

반응형

함수 찾는 순서

  • 1순위 정확한 매칭(exactly matching) 
  • 2순위 템플릿(template)
  • 3순위 가변 인자(variable argument)
#include <iostream>
using namespace std;

template<typename T>
// 2순위 템플릿(template)
void foo(T t) { cout << "T" << endl; }
// 1순위 정확한 매칭(exactly matching)
void foo(int n) { cout << "int" << endl; }
// 3순위 가변 인자(variable argument)
void foo(...) { cout << "..." << endl; }

int main()
{
    foo(3);
}

 

SFINAE

  • Substitution Failure Is Not An Error

  • 함수 템플릿을 사용시 T의 타입이 결정되고 함수를 생성(Instantiation)하려고 할때 리턴 타입이나 함수 인자등에서 치환에 실패하면 컴파일 에러가 아니라, 함수 후보군에서 제외함

  • 동일한 이름의 다른 함수가 있다면 다른 함수를 사용하게 됨

#include <iostream>
using namespace std;

template<typename T>
typename T::type foo(T t) 
{ 
    cout << "T" << endl; return 0; 
}

void foo(...) 
{ 
    cout << "..." << endl; 
}

int main()
{
    // 가변인자 함수보다 템플릿 함수가 우선순위가 높아서 먼저 참조하게 되지만 리턴 타입에서 
    // int 타입::type은 존재하지 않으므로 만족할 수 없으므로 후보군에서 제외되고 가변인자 버전의 함수가 사용됨
    foo(3); // T
}

 

enable_if

  • c++표준에서 지원하는 도구

  • 1번째 인자가 true일 경우만 type이 정의됨

    • enable_if<true, int>::type  -> int

    • enable_if<true>::type -> void

    • enable_if<false, int>::type -> error

    • enable_if<false>::type -> error

#include <iostream>
using namespace std;

template<bool b, typename T = void> struct enable_if
{
};

template<typename T> struct enable_if<true, T>
{
    typedef T type;
};

int main()
{
    //enable_if<true, int>::type t0; // 타입이 int로 결정
    //enable_if<true>::type t1; // 타입이 void로 결정
    //enable_if<false, int>::type t2; // 타입이 없어서 error
}

 

enable_if 예제

  • 정수일때만 동작하는 함수를 만들고 싶을때

    • static_assert

      • 처리하게 되면 조건을 만족하지 않을 경우 컴파일 에러

    • enable_if

      • SFINAE 특성을 활용한 방법

      • 조건을 만족하지 않으면 함수를 생성하지 않고 다른 후보가 있다면 사용함

      • 확장성 유리

#include <iostream>
using namespace std;

// 정수일때만 함수 코드를 생성하고 싶음
template<typename T>
typename enable_if<is_integral<T>::value, int>::type
foo(T a)
{
    cout << "T" << endl;

    return 0;
}

void foo(...)
{
    cout << "not integer" << endl;
}

int main()
{
    foo(2.3);
}

 

enable_if 위치

  • 함수 리턴 타입

  • 함수 인자 타입 -> 생성자에서 주로 사용

  • 템플릿 인자 -> 함수 자체의 모양이 단순해 보이는 장점 있음

#include <iostream>
using namespace std;

// 함수 리턴 타입 위치
template<typename T>
typename enable_if<is_integral<T>::value, int>::type
foo(T a)
{
    cout << "T" << endl;

    return 0;
}

// 함수 인자 타입 위치(리턴 타입이 없는 생성자에서 주로 사용)
template<typename T>
void foo(T a, 
    typename enable_if<
    is_integral<T>::value>::type* = nullptr)
{
    cout << "T" << endl;
}

// 템플릿 인자(함수 자체의 원형이 최대한 유지됨으로 간결해 보이는 장점)
template<typename T, 
    typename enable_if<
    is_integral<T>::value>::type* = nullptr>
void foo(T a)
{
    cout << "T" << endl;
}

// 모두 만족하지 않을때 호출
void foo(...)
{
    cout << "not integer" << endl;
}

int main()
{
    foo(2); // 템플릿 함수 호출(현재 예제코드는 3개의 템플릿이 만족함으로 에러 발생함)
    foo(2.3); // foo(...) 호출
}

 

타입의 종류에 따라 다르게 동작하는 함수 생성 방법

  • type_traits(is_pointer) + if constexpr // C++17에서만 가능
  • type_traits + 함수 오버로딩(false_type, true_type)
    • 디스패치 함수 1개 더 필요
  • type_traits + enable_if
// C++17이상 가능 if constexpr 사용 방법

#include <iostream>
using namespace std;

template<typename T> void printv(const T& v)
{
    if constexpr(is_pointer<T>::value)
        cout << v << ":" << *v << endl;
    else
        cout << v << endl;
}

int main()
{
    int n = 0;
    printv(n);
    printv(&n);
}
// type_traits + 함수 오버로딩(false_type, true_type)

#include <iostream>
using namespace std;

template<typename T>
void printv_imp(const T& v, true_type)
{
    cout << v << ":" << *v << endl;
}

template<typename T>
void printv_imp(const T& v, false_type)
{
    cout << v << ":" << endl;
}

template<typename T> void printv(const T& v)
{
    printv_imp(v, is_pointer<T>());
}

int main()
{
    int n = 0;
    printv(n);
    printv(&n);
}
// type_traits + enable_if 사용 방법

#include <iostream>
using namespace std;

template<typename T> 
typename enable_if<is_pointer<T>::value>::type 
printv(const T& v)
{
    cout << v << ":" << *v << endl;
}

template<typename T> 
typename enable_if<!is_pointer<T>::value>::type
printv(const T& v)
{
    cout << v << ":" << endl;
}

int main()
{
    int n = 0;
    printv(n);
    printv(&n);
}
반응형

반응형

Policy Based Design

  • 클래스가 사용하는 정책을 템플릿 인자를 통해서 교체 할 수 있게 만드는 디자인

  • 성능 저하 없이 정책을 교체 할 수 있음

  • 대부분의 정책은 담은 "단위 전략 클래스"는 지켜야 하는 규칙이 있음

    • 규칙을 표현하는 코딩 방식은 없음(인터페이스 사용시 가상 함수이므로 약간의 오버헤드 발생), C++20 concept 문법

    • 우리가 만든 동기화 정책클래스는 "lock/unlock" 함수가 필요함

    • 템플릿 기반 라이브러리, 특히 STL에서 널리 사용되는 디자인 기법

#include <iostream>
using namespace std;

// 1개의 클래스로 정책 템플릿 인자를 통해서 다르게 구현 할 수 있도록 디자인
template<typename T, typename ThreadModel> class List
{
    ThreadModel tm;
public:
    void push_front(const T& a)
    {
        tm.lock();
        // 구현부 코드
        tm.unlock();
    }
};

// 싱글 쓰레드 기반 환경용
class NoLock
{
public:
    inline void Lock() {};
    inline void Unlock() {}
};

// 멀티 쓰레드 기반 환경용
class MutexLock
{
public:
    inline void Lock() {};
    inline void Unlock() {}
};

// 환경에 따라서 클래스 생성 시 전략을 선택 할 수 있음
// 싱글 쓰레드용 생성
//List<int, NoLock> s;
// 멀티 쓰레드용 생성
List<int, MutexLock> s;

int main()
{
    s.push_front(10);
}

 

STL allocator

  • C++에서 메모리 할당 방법은 다양함

    • new, malloc, calloc, win32 api, linux system call

  • STL에서는 각 데이터 컨테이너의 템플릿 인자로 메모리 할당 방식에 대한 전략을 선택할 수 있도록 지원함

#include <iostream>
using namespace std;

// STL의 Vector 생각
// 메모리 할당기
template<typename T> class allocator
{
public:
    T* allocate() {}
    void deallocate() {}
};

template<typename T, typename Ax = allocator<T>> class vector
{
    T* buff;
    Ax ax;
public:
    void resize(int n)
    {
        // 버퍼 재할당이 필요하다면 어떻게 할까요?
        // new, malloc, calloc, win32 api, linux system call
        T* p = ax.allocate(n);
        ax.deallocate(p);
    }
};

int main()
{
    vector<int, MyAlloc<int>> v(10);
    v.resize(20);
}

 

rebind

#include <iostream>
using namespace std;

template<typename T> class allocator
{
public:
    T* allocate(int sz) { return new T[sz]; }
    void deallocate(T* p) { delete[] p; }

    template<typename U> struct rebind
    {
        typename allocator<U> other;
    };
};

template<typename T, typename Ax = allocator<T> > class list
{
    struct NODE
    {
        T data;
        NODE* next, * prev;
    };
    //Ax ax; // allocator<int>
    //allocator<int>::rebind<NODE>::other ax; // allocator<NODE> ax;
    typename Ax::template rebind<NODE>::other ax; // allocator<NODE> ax;
public:
    void push_front(const T& a)
    {
        ax.allocate(1);
    }
};

int main()
{
    list<int> s;
    s.push_front(10);
}
반응형

반응형

CRTP 활용한 싱글톤(Singleton) 만들기

  • 싱글톤: 하나의 객체만 생성 할 수 있게 만드는 디자인 패턴
    • private 생성자
    • 복사와 대입 금지
    • 하나의 객체를 만들어서 리턴하는 static 멤버 함수

단일 Singletone 패턴 클래스

#include <iostream>
using namespace std;

class Cursor
{
private:
    Cursor() {}
public:
    Cursor(const Cursor& c) = delete;
    void operator=(const Cursor& c) = delete;

    static Cursor& getInstance()
    {
        static Cursor instance;
        return instance;
    }

};

int main()
{
    Cursor& c1 = Cursor::getInstance();
    Cursor& c2 = Cursor::getInstance();
}

CRTP 패턴 Singleton 패턴 클래스

#include <iostream>
using namespace std;

template<typename T>
class Singleton
{
protected:
    Singleton() {}
public:
    Singleton(const Singleton& c) = delete;
    void operator=(const Singleton& c) = delete;

    static T& getInstance()
    {
        static T instance;
        return instance;
    }
};

class Mouse : public Singleton<Mouse>
{
};

int main()
{
    Mouse& m1 = Mouse::getInstance();
    Mouse& m2 = Mouse::getInstance();
}

 

CRTP 활용한 Unique한 기반 클래스 만들기

  • 기반 클래스의 static memeber data는 모든 파생 클래스에 의해 공유됨

  • 파생 클래스 별로 다른 static member data가 필요한 경우, 서로 다른 기반 클래스를 사용해야 함

  • CRTP를 사용하면 모든 파생 클래스 별로 다른 타입의 기반 클래스를 만들 수 있음

static 멤버 데이터를 관리하는 단일 클래스

#include <iostream>
using namespace std;

class Object
{
public:
    static int cnt;

    Object() { ++cnt; }
    ~Object() { --cnt; }

    static int getCount() { return cnt; }
};
int Object::cnt = 0;

int main()
{
    Object c1, c2;
    cout << c1.getCount() << endl;
}

static 멤버 데이터를 관리하는 유일한 기반 클래스

#include <iostream>
using namespace std;

template<typename T>
class Object
{
public:
    static int cnt;

    Object() { ++cnt; }
    ~Object() { --cnt; }

    static int getCount() { return cnt; }
};
template<typename T> int Object<T>::cnt = 0;

class Mouse : public Object<Mouse>
{

};

class Keyboard : public Object<Keyboard>
{

};

int main()
{
    Mouse m1, m2;
    Keyboard k1, k2;
    cout << m1.getCount() << endl;
    cout << k1.getCount() << endl;
}
반응형

+ Recent posts