cppmap.docs icon indicating copy to clipboard operation
cppmap.docs copied to clipboard

C++ の面白いコード、トリッキーなコードの話

Open Reputeless opened this issue 5 years ago • 21 comments

実用性はなくてもいいので、面白いネタ的なコードや不思議な文法、仕様のハックなどがあれば教えてください。ある程度たまったら記事にします。

  • 数行~十数行で完結するぐらいが好ましいです
  • マイナーなものでも有名なものでも OK です

(例) コメントアウトのトリック

Reputeless avatar Mar 12 '19 11:03 Reputeless

よくある、ヘッダファイル以外をインクルードするとかは、データをコンパイル時に埋め込める便利な記法です。

int ar[] = {
    #include "a.csv"
};

ヘッダファイル内で.cpp (相当のファイル) をインクルードするオプションを用意して、ヘッダオンリー化できるようにしているのとかは、ライブラリを作るにあたって設計選択のひとつになっています。

https://github.com/boostorg/chrono/blob/develop/include/boost/chrono/thread_clock.hpp

(最近はシングルヘッダ版を自動生成するとかもありますが)

faithandbrave avatar Mar 12 '19 12:03 faithandbrave

プリプロセス関係だと、文字列リテラルの結合とかも、マイナーですがたまに便利ですね。自前のprintfやassertを作るときにも使いますし、長い文字列リテラルを分割して書くのにも便利です。

#include <cstdio>

#define INFO(fmt, ...) std::printf("[info] " fmt "\n" __VA_OPT__(,) __VA_ARGS__)
#define DEBUG(fmt, ...) std::printf("[debug] " fmt "\n" __VA_OPT__(,) __VA_ARGS__)

int main()
{
    INFO("hello");
    DEBUG("hello %d", 123);
}
#include <iostream>

int main()
{
    std::string help = "The application is designed by ME.\n"
                       "Welcome my application";

    std::cout << help << std::endl;
}

faithandbrave avatar Mar 12 '19 12:03 faithandbrave

csvのインクルードとかを多用するようになると、以前私がブログに書いた以下のようなものがほしくなります。

faithandbrave avatar Mar 12 '19 12:03 faithandbrave

コメントありがとうございます! 引き続き募集してます。

--> 演算子

#include <iostream>

int main()
{
	int i = 10;

	while (i --> 0)
	{
		std::cout << i << '\n';
	}
}

Reputeless avatar Mar 12 '19 12:03 Reputeless

template関数のオーバーロードに優先順位を付けるやつ:

#include<cstdint>
template<std::size_t N>struct priority : priority<N-1>{};
template<>             struct priority<0>{};

#include<iostream>
#include<type_traits>
template<
  typename T,
  std::enable_if_t<std::is_same<std::decay_t<T>, float>::value, std::nullptr_t> = nullptr
>
void f_impl(T t, priority<1>){std::cout << "float " << t << std::endl;}
template<typename T>
void f_impl(T t, priority<0>){std::cout << "T " << t << std::endl;}

template<typename T>
void f(T&& t){f_impl(std::forward<T>(t), priority<1>{});}

int main(){
  f(3.1);
  f(3.14f);
  f("3.141592");
}

Wandbox

wx257osn2 avatar Mar 12 '19 14:03 wx257osn2

面白いかは分からないですが、リテラル0だけを受け取る関数(nullptrからは目を逸らして・・・)

struct minus {
  constexpr bool operator<(std::nullptr_t) {
    return true;
  }
  
  constexpr bool operator>(std::nullptr_t) {
    return false;
  }
};

void f(std::nullptr_t) {
  std::cout << "literal 0" << std::endl;
}

https://wandbox.org/permlink/sDe2GzeQuPk1hMT0

onihusube avatar Mar 12 '19 15:03 onihusube

コンパイルできそうだけどできないコードたち

void f2(std::shared_ptr<int>=0);
void f(int*=0);
int a[3];
a[[]{return 0;}()];

https://wandbox.org/permlink/P76EMNyoE6FAQaDs

Fuyutsubaki avatar Mar 12 '19 16:03 Fuyutsubaki

false_vを作らないでlambda式でif constexpr内のstatic_assertの評価を遅延させるやつ

#include <type_traits>

template <typename T>
void f(T)
{
  if constexpr (std::is_same_v<T, int>)
  {
    // Tがintのときのみ評価される
    static_assert([]{return false;}());
  }
}

int main()
{
  f(2.4);
  f(3);
}

https://cpprefjp.github.io/lang/cpp17/if_constexpr.html https://github.com/cpprefjp/site/pull/577 by @alphya

yumetodo avatar Mar 13 '19 04:03 yumetodo

input streamの中身をまるごとoutput streamにぶちこむやつ

os << is.rdbuf();

yumetodo avatar Mar 13 '19 04:03 yumetodo

Most vexing parse: https://en.wikipedia.org/wiki/Most_vexing_parse

rhysd avatar Mar 14 '19 11:03 rhysd

暗黙の型変換にやられるやつ(ただのバグ)

#include <iostream>

int main()
{
    if(-1 < 1u)
    {
        std::cout << "-1 < 1u";
    }
    else
    {
        std::cout << "-1 > 1u";
    }
}

agehama avatar Mar 14 '19 13:03 agehama

名前空間の付け忘れにやられるやつ(ただのバグ)

#include <iostream>
#include <cmath>

int main()
{
    //std::cout << std::abs(0.5); // 0.5
    std::cout << abs(0.5);        // 0
}

agehama avatar Mar 14 '19 13:03 agehama

template <int>
int a = 0;

int main() {
    //a<10>= 1; // 動かない
    a<10> = 1;
}

スペースの有無で演算子と解釈されるかどうか異なります

nekko1119 avatar Mar 16 '19 08:03 nekko1119

(特別C++に限らないけけど) Fast inverse square root とか

Fuyutsubaki avatar Mar 18 '19 03:03 Fuyutsubaki

https://wandbox.org/permlink/fXQKYqQAgMiyMMf9

  • enumをコンパイル時定数として使う
  • enumの最後の要素を要素数として使う
  • 配列の変数名とインデックスを逆にしても動作する

zxc-key avatar Oct 27 '20 12:10 zxc-key

constexprが普通に使えるこんにちは出番がなさそう・・・?

yumetodo avatar Oct 27 '20 12:10 yumetodo

@zxc-key 提案ありがとうございます。

  1. enum をコンパイル時定数として扱うのは今では古いテクニック (現在は constexpr) で、ある程度知られているとも思います
  2. 「最後尾 = 要素数」は、サンプルコードでいうと _0 = 100 のようなコードで不正になります。magic_enum というライブラリの enum_count では、複雑なテクニックでその問題も回避しています
  3. cppmap 掲載済みです https://cppmap.github.io/articles/it-compiles/#_2

【面白いネタ的なコードや不思議な文法】として cppmap で新規に取り上げるネタはありませんでしたが、また面白いコードを見つけたら教えてください 🖐

Reputeless avatar Oct 27 '20 13:10 Reputeless

int main()
{
  []{};
  []{}();
  [](){};
  [](){}();
  [[]][]{};
  []()[[]]{};
  [[]][]{}();
  [[]][](){};
  []()[[]]{}();
  [[]][](){}();
  [[]][]()[[]]{};
  [[]][]()[[]]{}();
}

ネタの一つとして提供:https://twitter.com/yohhoy/status/1367790416007897089

yohhoy avatar Mar 05 '21 14:03 yohhoy

#include <iostream>

using T = int&;
void f(T&) { std::cout << "non-const" << std::endl; }
void f(const T&) { std::cout << "const" << std::endl; }

int main() {
  int x;
  f(x);
}

コンパイルできそうでできないやつです。

yaito3014 avatar Mar 07 '21 08:03 yaito3014

#include <type_traits>
using T = int&;
using T2 = const T&;
static_assert(std::is_same_v<T, T2>);

なるほど・・・? https://wandbox.org/permlink/SVngPcUtKYXAL72O

yumetodo avatar Mar 07 '21 11:03 yumetodo

長い演算子 (演算子の優先順位的にできるやつ)

#include <iostream>

int main() {
  int a = 10, b = 10;
  a = a +-+-+-+-+-+-+-+-+ 6 +-+-+-+-+-+-+-+-+ 5;
  b = b + + + + + + + + + 6 - - - - - - - - - 5;
  std::cout << a << '\n';
  std::cout << b << '\n';
  return 0;
}

Ryoga-exe avatar Mar 08 '21 14:03 Ryoga-exe