Skip to content

Instantly share code, notes, and snippets.

@pabigot
Last active August 29, 2015 13:55
Show Gist options
  • Save pabigot/8755520 to your computer and use it in GitHub Desktop.
Save pabigot/8755520 to your computer and use it in GitHub Desktop.
Support for Diagnostics in Template Metaprogramming
#include <string>
#include <type_traits>
/* Provide the algorithm only if the expectations are met */
template <typename T1, typename T2,
typename = typename std::enable_if<std::is_assignable<T1, T2>::value>::type>
void useit (T1& t1, T2 t2)
{
t1 = t2;
}
int main ()
{
std::wstring s1{L"wide"};
std::string t1{"narrow"};
useit(t1, s1);
}
# Normal use is GNUC in $(GCC_ROOT).
# Alternative is clang++ in $(CLANG_ROOT), enable with WITH_CLANG=1
# libc++ enabled with WITH_LIBCPP=1 (defaults WITH_CLANG=1)
CXX_STD=c++1y
GCC_ROOT=/usr/local/gcc
CLANG_ROOT=/usr/local/clang
# This is how libc++ spells itself; it's not a C preprocessor library
WITH_LIBCPP ?= 0
WITH_CLANG ?= $(WITH_LIBCPP)
WARN_CXXFLAGS=-Wall -Werror
OPT_CXXFLAGS=-g -O2
CPPFLAGS=-DWITH_BOOST=$(WITH_BOOST) $(AUX_CPPFLAGS)
CXXFLAGS=-std=$(CXX_STD) $(WARN_CXXFLAGS) $(OPT_CXXFLAGS) $(AUX_CXXFLAGS)
LDFLAGS?=
LINK.o=$(LINK.cc)
ifneq ($(WITH_CLANG), 0)
TOOLCHAIN_ROOT=$(CLANG_ROOT)
CXX=$(CLANG_ROOT)/bin/clang++
ifneq ($(WITH_LIBCPP), 0)
CPPFLAGS += -I$(CLANG_ROOT)/include/c++/v1
CXXFLAGS += -stdlib=libc++
LDFLAGS += -L$(CLANG_ROOT)/lib/ -Wl,-rpath,$(CLANG_ROOT)/lib/
endif # WITH_LIBCPP
else # WITH_CLANG
TOOLCHAIN_ROOT=$(GCC_ROOT)
CXX=$(GCC_ROOT)/bin/g++
endif # WITH_CLANG
LDFLAGS += -Wl,-rpath,$(TOOLCHAIN_ROOT)/lib64:$(TOOLCHAIN_ROOT)/lib32:$(TOOLCHAIN_ROOT)/lib
CLEAN ?=
REALCLEAN ?=
CASES = no-check ei-check sa-check sa-helper-check
all: $(CASES:%=%.err)
CLEAN += *.err
%.err: %.cc
-$(LINK.cc) $^ $(LDLIBS) > $@ 2>&1
.PHONY: clean realclean
clean:
-rm -rf $(CLEAN)
-rm -f *.o *~
realclean: clean
-rm -rf $(REALCLEAN)
#include <string>
template <typename T1, typename T2>
void useit (T1& t1, T2 t2)
{
t1 = t2;
}
int main ()
{
std::wstring s1{L"wide"};
std::string t1{"narrow"};
useit(t1, s1);
}
#include <string>
#include <type_traits>
template <typename T1, typename T2>
void useit_ (T1& t1, T2 t2)
{
t1 = t2;
}
/* Generate a diagnostic if the expectations aren't met, but defer the
* mis-use to another function */
template <typename T1, typename T2>
void useit (T1& t1, T2 t2)
{
static_assert(template_types_ok::value, "cannot assign T2 to T1");
useit_(t1, t2);
}
int main ()
{
std::wstring s1{L"wide"};
std::string t1{"narrow"};
useit(t1, s1);
}
#include <string>
#include <type_traits>
/* Provide the algorithm only if the expectations are met */
template <typename T1, typename T2,
typename = typename std::enable_if<std::is_assignable<T1, T2>::value>::type>
void useit_ (T1& t1, T2 t2, std::true_type template_types_ok)
{
t1 = t2;
}
/* Provide a no-op that doesn't produce errors when the expectations
* are not met. */
template <typename T1, typename T2>
void useit_ (T1&, T2, std::false_type template_types_ok)
{ }
/* Bleat in distress when the template types don't satisfy
* expectations, but unconditionally delegate to an implementation
* that won't produce compiler errors in either case. */
template <typename T1, typename T2>
void useit (T1& t1, T2 t2)
{
using template_types_ok = std::is_assignable<T1, T2>;
static_assert(template_types_ok::value, "cannot assign T2 to T1");
useit_(t1, t2, typename template_types_ok::type());
}
int main ()
{
std::wstring s1{L"wide"};
std::string t1{"narrow"};
useit(t1, s1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment